6.访问权限控制
6.1 包:库单元
一个java源代码文件,称为一个编译单元
单个编译单元中,只允许出现一个public类(可以存在多个非public类)
每个类都会生成一个.class文件
6.1.1 代码组织
- 工作方式:Java可运行程序是一组可以打包并压缩为一个Java文档文件(JAR)的.class文件
- 类库:一组类文件,使用关键字package。每个文件包含一个public类,任意数量的非public类(用于服务public类)
package
-
规则
-
必须为除文件注释外的第一句程序代码
-
格式:package access
代表该编译单元为access的类库的一部分
-
全部使用小写字母
-
使用import关键字导入指定类
import access.mypackage.*;
-
-
package和import功能
- 将单一的全局名字空间分割开,防止类名称冲突
6.1.2 创建唯一的包名
-
包名组成
- 第一部分是Internet域名的反顺序。
- 第二部分为机器上的目录
-
CLASSPATH
- 编译器碰到类库的import语句,会在CLASSPATH指定的目录中查找
-
类的同名冲突
-
情况:将两个包含相同名称的类库同时以*导入时,使用两个共有的类,将产生冲突
-
解决方法:完全指明需要使用的类的位置
// 假设两个类库都包含Vector类 import net.value.*; import java.util.*; // 产生冲突的情况 Vector v = new Vector(); // 解决方法 java.util.Vector v = new java.util.Vector();
-
6.1.3 定制工具库
public static void print(Object obj){
System.out.println(obj);
}
6.1.4 用import改变行为
-
条件编译:源代码中,部分代码在满足条件下才编译
-
方法
-
使用import改变行为
-
使用判断条件为常量的if语句,根据if判断条件的真假,编译器直接把分支为false的代码块消除
以下方法,final常量的代码块将消除
// 空方法 public void voidMethod(){ } //final常量 private final boolean FINAL_FLAG_FALSE = false; public void constantFalseFlag(){ if(FLAG_FALSE){ System.out.println("debug log..."); } } // 非final private boolean falseFlag= false; public void falseFlag(){ if(falseFlag){ System.out.println("debug log..."); } }
-
6.2 Java访问权限修饰词
6.2.1 包访问权限
- 规则
- 不提供访问权限修饰词,代表“包访问权限”
- “包访问权限”代表只有在同一个package中的成员,才能互相访问
- 取得访问成员的途径
- 成员的访问权限修饰词为public
- “包访问权限”中,处于同一个包中的成员之间互相访问
- 通过继承的方式访问,继承而来的类允许访问public和protected成员,但不允许访问private成员
- 提供getter和setter方法访问,这是最优雅的方式,也是javabean的基本原理
6.2.2 public:接口访问权限
[外链图片转存失败(img-pytT6AHA-1563897704559)(/Users/toyz/Package/Note/Thinking in Java/Public访问权限.png)]
- public任意成员皆可访问
默认包
- 不提供访问修饰词,且在同一个folder中(非package中),会默认将类放置在“默认包”中,因此Cake可以创建Pie对象,调用f()方法
6.2.3 private:无法访问
-
规则
- 除包含该成员的类之外,任何其他类都无法访问这个成员
-
用途
-
是类的“助手”方法的方法。比如控制如何创建对象,阻止直接访问特定的构造器
-
可以将类中的变量和方法用private修饰
// 控制创建的对象 Class Sundae{ private Sundae(){} static Sundae makeSundae(){ return new Sundae(); } } public class IceCream{ public static void main(String[] args){ // 控制使用makeSundae()方法来创建对象 Sundae s = Sundae.makeSundae(); } }
-
6.2.3 protected:继承访问权限
-
继承:利有现有类,也就是基类,将新成员添加到基类中而不需要修改基类的,还可以改变基类中现有成员的行为的方法
-
规则
- 继承类能够访问基类的protected成员
- protected提供包访问权限
-
注意点
-
protected是指子类可以访问、重写(即使不在同一个包中)。因此当子类继承基类,创建子类对象可以访问基类中的protected成员。而不是创建基类对象,访问基类中的protected成员。
-
相同目录下,所有不具有明确package声明的文件,都视为默认包的一部分
// 基类 public class TestProtected { protected void pro(){}; } // 子类 public class TestAll extends TestProtected { public static void main(String[] args) { TestAll ta = new TestAll(); ta.pro(); } }
public class TestAll { public static void main(String[] args) { // public 方法调用,成功,因为任意访问权限 TestPublic tpub = new TestPublic(); tpub.pub(); // protected 方法调用,成功,因为包访问权限 TestProtected tpro = new TestProtected(); tpro.pro(); // private 方法调用,失败 TestPrivate tpri = new TestPrivate(); // tpri.pri(); } }
-
6.3 接口和实现
-
封装:把数据和方法包装进类中,以及具体实现的隐藏
-
访问控制权限将权限边界划在数据类型的内部原因
- 设定客户端程序员可以使用和不可以使用的边界
- 将接口和具体实现分离。客户端程序员仅可以向接口发送信息,防止破坏客户端代码
6.4 类的访问权限
-
规则
- 类的访问权限关键字必须出现在关键字class之前
-
限制
-
每个编译单元只能有一个public类
因为编译的时候Java编译器会判断如果存在public类,该类当作这个编译单元的对外接口,类加载器需要把该类加载。
-
public的类名称必须和编译单元的文件名匹配,包括大小写
-
存在编译单元内没有public类,因此可以随意命名文件——但不提倡
-
-
注意点
-
类的访问权限只有public和包访问权限两种
-
-
当构造器为private时,如果创建对象
-
方法一:创建一个static方法,方法创建对象,并返回引用
class Soup1{ private Soup1(){}; public static Soup1 makeSoup1(){ return new Soup1; } }
-
方法二:单例模式,始终只能创建它的一个对象
class Soup2{ private static Soup2 sp = new Soup2(); public static Soup2 access(){ return sp; } }
-