《Java从入门到失业》第四章:类和对象(4.5):包

2024-04-10 12:38

本文主要是介绍《Java从入门到失业》第四章:类和对象(4.5):包,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

点击“Finish”按钮,我们发现,工程目录多了一个包,然后我们在包目录上点击右键,创建一个类PackageTest,Eclipse会自动生成代码如下:

package com.javadss.javase.ch04;

public class PackageTest {

}
我们发现,该文件的第一行多了一句代码:

package com.javadss.javase.ch04;
这句代码的含义就是表示该源文件中的所有类都将被放到包com.javadss.javase.ch04的下面。如果我们在该源文件中继续写一个类PackageTest2如下:

复制代码
package com.javadss.javase.ch04;

public class PackageTest {

}

class PackageTest2 {

}
复制代码
这样源文件PackageTest.java中的2个类PackageTest和PackageTest2 都被放到包com.javadss.javase.ch04中了。因此它们的完整类名分别为:

com.javadss.javase.ch04.PackageTest

com.javadss.javase.ch04.PackageTest2

假如我们的源文件开头没有声明包语句,那么这个源文件会被放置到一个默认包中,默认包是一个没有名字的包,像我们之前的例子,都没有声明包,因此它们都是放置在默认包中的。不过在实际运用中,非常不推荐把类放置在默认包中。

   定义好了类的包后,我们看看这个源文件被放在什么地方了。笔者的Eclipse的工作空间目录为D:\Java大失叔\workspace,本书的工程为BaseJava,工程中src为源代码目录,bin为class文件目录。则最终源文件PackageTest.java的路径为:

D:\Java大失叔\workspace\BaseJava\src\com.javadss.javase.ch04\PackageTest.java

目录层次结构如下:

因为我们使用了Eclipse,它会自动帮我们编译类,还记得我们在3.1演示HelloWorld的时候教大家如何创建工程吗?Eclipse创建工程默认会使用项目文件目录作为根目录,下面会创建2个文件夹:src和bin。src用来存放源代码文件,bin用来存放编译后的字节码class文件。我们会发现,最终src和bin变成如下结构:

实际上,如果我们不用IDE,我们手工在src目录下编写上述源文件,然后用命令行工具编译(我们也编译到bin目录下),命令如下(还记得编译命令吗?红色表示编译后的class文件的目录,蓝色表示源文件的路径):

javac -d D:\Java大失叔\workspace\BaseJava\bin D:\Java大失叔\workspace\BaseJava\src\com\javadss\javase\ch04\PackageTest.java

编译成功后,也会在bin目录下形成上述结构。

4.5.3包作用域
  上面我们说过包可以用来解决同名类的冲突问题,实际上,包还有一个作用,就是可以控制权限。

前面我们接触过访问修饰符public、private,其实还有一个protected,它们可以用来修饰类、属性及方法,当类、属性或方法不用任何访问修饰符修饰的时候,我们可以认为有一个default修饰符在修饰它们,这样一来,可以认为有4种访问修饰符,这4个修饰符可以控制对同一个类、同一个包、不同包的子类、不同包非子类的访问权限,下面我们用表格的形式列出它们的权限范围:

同一个类

同一个包

不同包子类

不同包非子类

public

protected

default

private

我们看到,当不用任何修饰符修饰的时候,类、方法和属性对同一个包下的其他类是开放的。我们用一个例子演示一下,看如下2个类:

复制代码
package com.javadss.javase.ch04;

class PackageTest {
private String sPrviate = “我是私有的”;
String sDefault = “我是默认的”;

void testYes() {  System.out.println("同一个包可以访问我");  
}  private void testNo() {  System.out.println("只有我自己可以访问我");  
}  

}
复制代码
复制代码
package com.javadss.javase.ch04;

class PackageTest2 {
public static void main(String[] args) {
PackageTest test = new PackageTest();
test.testYes();
System.out.println(test.sDefault);
}
}
复制代码
我们看到,PackageTest和PackageTest2在同一个包中,因此PackageTest2可以访问PackageTest的testYes方法和sDefault属性,但是不能访问private修饰的testNo方法和sPrivate属性。

   这里其实有一个问题,就是PackageTest2可以修改PackageTest的sDefault属性,其实对于有些情况来说,算是破坏了封装性。比如我编写了一个小工具类DssUtil提供给别人使用,包名是com.javadss.util。其中有很多默认修饰的属性,我本意是不想对外界开放。但是实际上使用者可以把他的类也放到包com.javadss.util中,这样他的类就可以随意访问DssUtil中的默认修饰属性了。不过这一点也有办法控制,后面我们有机会可以讨论包密封机制来解决这个问题(Java虚拟机从类加载上禁止加载用户自定义的以java.开头的类来解决这个问题)。另外,还有一个问题需要注意,包并没有包含关系,例如对于包com.javadss.javase和com.javadss.javase.ch04这是2个包,因此这2个包下的类,不能互相访问默认作用域的类、属性和方法。

4.5.4包的导入
  一个类可以访问同包中的所有类和其他包中的public类,如果需要访问其他类,需要导入以后才能访问。导入类有几种方式,我们一一介绍。

4.5.4.1直接写完整类名
第一种方式,是直接写完整类名。例如我们要使用Arrays类对一个数组排序,可以这样:

复制代码
class PackageTest2 {
public static void main(String[] args) {
int[] a = new int[] { 4, 1323, 1, 33 };
java.util.Arrays.sort(a);//直接写完整类名
}
}
复制代码
但是这种方式显然是比较痛苦和令人讨厌的,一般我们采用下面这种方式。

4.5.4.2import语句
第二种方式就是用import语句导入。import语句可以导入某个特定的类或导入整个包。例如:

import java.util.Arrays;//导入特定的类
或者

import java.util.*;//导入整个包
使用import语句导入后,就可以不用写完整类名了。这里需要注意的是,导入整个包的方式,并不能把子包导入进来。一般情况下,我们推荐导入特定类的方式,这样可以直接看到某个类在哪个包下。

   聪明的同学可能要问了,我记得我们之前一直使用System类来打印,但是好像也没有导入包啊?算你厉害,这里就牵涉到编译器在编译的时候,是如何定位类的:

如果是完整类名,则直接定位到该类
如果是简单类名,则按下面顺序:
从当前包下查找是否存在该类
从import语句中查找是否存在该类
从java.lang包中查找是否存在该类
看到了吗?实际上就相当于编译器会帮我们导入当前包和java.lang包下的类。因为System是java.lang包下的类,因此我们可以不必显式的导入。

   有的时候还存在一个问题,当2个包下存在同名的类时,比如在JDK中存在java.util.Date和java.sql.Date,如果我们用了如下语句:

import java.util.;
import java.sql.
;
那么我们无法使用简单的类名Date。因为无法区分是用哪个包下的Date类。假如我们只使用其中一个,比如我们用java.util.Date,可以有一个取巧的办法:

import java.util.;
import java.sql.
;
import java.util.Date;
但是这种办法解决不了我们同时需要使用2个Date类。如果同时需要使用的时候,只能用完整类名的方式了。

4.5.4.3静态导入
从Java5.0开始,增加一种新的导入方式,可以导入静态方法和静态属性。前面我们经常使用System.out.println()来打印,其实out就是System类的一个静态属性。如果我们在源文件进行如下导入:

import static java.lang.System.out;
这样我们就可以直接使用out.println()来打印输出了:

复制代码
1 package com.javadss.javase.ch04;
2
3 import static java.lang.System.exit;
4 import static java.lang.System.out;
5
6 class PackageTest2 {
7 public static void main(String[] args) {
8 out.println(“静态导入”);
9 exit(0);
10 }
11 }
复制代码
注意看第3行,exit()是System的一个静态方法,这里不管这个方法有啥用,只是演示可以导入静态方法。当然,我们可以静态导入整个类的静态属性和方法:

import static java.lang.System.*;
龙华大道1号https://www.cnblogs.com/javadss/p/13716150.html

这篇关于《Java从入门到失业》第四章:类和对象(4.5):包的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/891085

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定