第六章 访问权限控制
6.1 包:库元素
解决一定的方法冲突问题。
- 每一个编译单元即(.java文件)只能有一个public类
- 如果使用package语句,该语句必须位于第一句
- java包命名规则默认使用小写
6.1.2 创建独一无二的包名
包下面的.class文件不会被打包成一个文件,而是利用操作系统的目录结构进行存储的。
引出的问题:怎样创建独一无二的名称;怎样查找隐藏在目录中的类
- 创建独一无二的名称:Internet域名是独一无二的。利用域名的反顺序。
- 路径查找:Java解释器首先找到环境变量(CLASSPATH),在此目录中找到.class文件的根目录。从根目录开始,Java解释器将package路径翻译成路径名称,然后再对应目录中找到.class文件。(如package foo.bar.baz --> foo/bar/baz)。
潜在的冲突:即在引用的所有包中存在相同的类名。这时不会报错,但是在使用的时候需要强制明确使用的类 。
6.1.3 定制工具库
6.1.4 用import改变行为
Java没有C的条件编译功能。
6.2 Java访问权限修饰词
6.2.1 包的访问权限
包的访问权限是默认的方式(即不添加任何修饰符)
统一包内的成员可以相互访问(除了private),并且不用添加路径引用。
CLASSPATH中的".;"是为了确保当前目录下的文件可以被编译。
6.2.2 public
该声明后的类、方法、变量都是可被外部人以访问的。
6.2.3 private
除了包含该成员的类之外,其他所有类都无法访问。
用途:
- 可以随意修改private成员,而不必考虑是否会影响到其他的类
- 控制对象的创建方式(如将构造器设置为peivate)
- 助手类方法可以设置为private
6.2.4 protected
应用场景:继承类。
注意点:
- protected提供包的访问权限。
- 如果创建一个类,继承自另外一个包的类,那么唯一能够访问的成员是源包public成员。
6.3 接口与实现
访问权限设置的好处
- 可以明确客户端程序员的使用权限。
- 接口与具体实现的分离:可以将接口定义成public,具体实现定义成private或protected。这样可以随意更改非public的东西。
6.4 类的访问权限
- 类的修饰符只能是默认的包权限或者public权限
- public类必须与文件名相同,包括大小写
如果不希望任何人对该类有访问权限,可以将所有构造器都设计成private。但是此时还有两种特例:①通过静态方法来创建该类对象(用于控制某类对象的个数);②通过静态方法返回该类对象的引用(单例模式)。
需要注意的是,要显式地将所有构造器设置成private,因为如果不设置构造器,编译器会自己生成一个默认的无参构造器,相当于该类还是看可以被创建。
// 通过静态方法来创建该类对象
class Soup1{
private static int instanceNum = 0;
private static final int maxNum = 5;
private Soup1(){}
public static Soup1 makeSoup(){
Soup1 sp = null;
if(Soup1.instanceNum < Soup1.maxNum){
sp = new Soup1();
Soup1.instanceNum++;
System.out.println("Create Soup1.");
}else
System.out.println("Exceed max num.");
return sp;
}
}
// 通过静态方法返回该类对象的引用(单例模式)
class Soup2{
private static Soup2 sp = new Soup2();
private Soup2(){}
public static Soup2 makeSoup(){
return Soup2.sp;
}
}
public class StaticCount {
public static void main(String[] args) {
// 测试情况1
for(int i = 1; i < 7; i++){
Soup1.makeSoup();
}
// 测试情况2
Soup2 s1 = Soup2.makeSoup();
Soup2 s2 = Soup2.makeSoup();
System.out.println(s1==s2);
}
}
// Create Soup1.
// Create Soup1.
// Create Soup1.
// Create Soup1.
// Create Soup1.
// Exceed max num.
// true
6.5 总结
6.5.1 类是如何被打包进一个类库的
通过package和系统目录结构。在查找时,将package翻译成系统目录,然后在CLASSPATH下进行查找。具体是通过强制包名与目录名相同。
6.5.2 类是如何控制成员访问的
- 包访问权限
包内可以访问protected成员 - public访问权限
- protected访问权限
继承自不同包的类时将无法访问父类中包访问权限的变量。 - private访问权限
封装与接口,将访问权限控制在内部;可以将实现与接口分离;
6.5.3 类的访问权限及特例
类只能使用包权限或者public权限。若设置为包权限,其他包将无法访问该类。如果不想任何人访问该类,可以显式地将构造器设置为private。但是有例外,及通过类的static方法、字段创建该类的对象。
6.5.4 权限控制的原因
- 防止客户触碰到不该触碰的部分,这些部分是内部操作必要而非客户端程序员需要。
- 可以允许类的创建者更改类内部的实现方式,但不必担心这样做对客户端程序员的影响。