【Java编程思想】6.访问权限控制
访问控制的初衷,是为了将变动的事物与需要保持不变的事务区分开来。
public>protected>''>private
6.1 包:库单元
当编写一个 Java 源代码文件是,此文件被称为编译单元(或是转译单元)。
- 每个编译单元必须有一个后缀名.java,而编译单元内则可以有一个 public 类,该类名称必须与文件相同(不包括后缀名)。
- 每个编译单元只能有一个 public 类,否则编译器不接受。
- 该编译单元中额外的类是无法被外部识别的,他们主要为主 public 提供支持
当编译一个.java 文件时,在.java 文件中的每个类都会有一个输出文件,该文件同名,只是后缀名为.class。
因此编译少量的.java 会产生大量的.class。
所以实际上 Java 可运行程序,就是一组可以打包并压缩为 jar 包的.class 文件,Java 解释器负责这些文件的查找、装载和解释。
package 和 import 关键字允许做的,是将单一的全局命名空间分隔开,不会出现名称冲突的问题。
Java 解释器的运行过程如下:
- 找出环境变量 CLASSPATH(可以通过操作系统来设置,也可以通过安装程序来设置),CLASSPATH 包含一个或多个目录-->用作查找.class 文件的根目录
- 从根目录开始,解释器获取包的名称,并将所有"."更换成""(是\还是/取决于操作系统),以从 CLASSPATH 根中产生一个路径名称。
- 得到的路径会与 CLASSPATH 中的各个不同的项相连接,解释器就在这些目录中查找,与所要创建的类名称相关的.class 文件。
当 import 两个包内有相同名称的类的时候,在使用时需要指定一方使用包含包名的完整类名。
6.2 Java 访问权限修饰词
取得对某成员的访问权限的途径:
- 使该成员成为 public。-->任何人都可以访问该成员。
- 通过不加访问权限修饰词,并将其他类放置于同一包内,给成员赋予包访问权。-->包内的其他成员都可以访问该成员。
- 使用继承,继承而来的类即可以访问 public 成员,也可以访问 protected 成员。
- 提供访问器(
accessor
)和变异器(mutator
)方法(也称作 get/set 方法),以读取和改变数值。
默认包的情况下(不在类上限定包),Java 会将这样的文件看做是隶属于该目录的默认包之中,于是他们可以被该目录中所有其他文件所访问。
protected 关键字处理的是继承的概念。
有时基类的创建者,会希望有某个特定成员,把对它的访问权限赋予给派生类,而不是所有类的时候,protected 可以完成这样的工作。
6.3 接口和实现
访问权限的控制常被称为是具体实现的隐藏。
把数据和方法包装进类中,以及具体实现的隐藏,常共同被称为封装。
访问权限控制将权限的边界,划在了数据类型的内部:
- 第一个原因是在结构中建立自己的内部机制,不用担心外部访问者将内部机制当做使他们可以使用的接口的一部分。
- 接口与具体实现的分离
6.4 类的访问权限
一些限制:
- 每个编译单元(文件)都只能有一个 public 类(代表着每个编译单元都有单衣的公共接口)。
- public 类的名称必须与含有该编译单元的文件名完全匹配。
- 编译单元内完全不带 public 也是可能的。这种情况下可以随意对文件命名。(不推荐使用的方式)
类不可以是 private 的,也不可一世 protected 的。
将一个类的所有构造器都指定为 private 可以组织其他人创建该类的对象。但是在该类的 static 成员内部还是可以创建该类的。eg.
class Soup1 {
private Soup1() {}
// (1) Allow creation via static method:
public static Soup1 makeSoup() {
return new Soup1();
}
}
class Soup2 {
private Soup2() {}
// (2) Create a static object and return a reference
// upon request.(The "Singleton" pattern):
private static Soup2 ps1 = new Soup2();
public static Soup2 access() {
return ps1;
}
public void f() {}
}
Soup2 中使用了单例设计模式,保证始终只能创建一个 Soup2 的对象,且只能通过 access 方法进行调用。