6.1 包:库单元
控制对成员的访问权限有两个原因:
第一,为了使用户不要碰触那些他们不该碰触的部分,这些部分对于类内部的操作时必要的,但是他并不属于客户端程序员所需接口的一部分。因此,将方法和域指定称private,对客户端程序员而言是一种服务。
第二,为了让类库设计者可以更改类的内部工作方式,而不必担心这样会对客户端程序员产生重大的影响。
访问权限控制专注于类库创建者和该类库的外部使用者之间的关系,这种关系是一种通信方式。
访问控制(或隐藏具体实现)与"最初的实现并不恰当"有关。换句话说就是:“我们的代码几乎不可能在一开始就做到最好,后期的迭代可以逐步改善情况,访问控制很大情况下就是为了后续代码的改善”。访问权限控制的等级,从最大权限到最小权限依次为:public、protected、包访问权限和private
import导入包。一般都是import java.util.*;
每一个Java文件只能有一个public类。
6.1.1 代码组织
当编译一个.java文件的时候,在.java文件中的每个类都会有一个输出文件,而该输出文件的名称和.java文件中的每个类相同,多了个后缀名.class。
Java可运行程序是一组可以打包并压缩为一个Java文档文件jar的.class文件。Java解释器负责这些文件的查找、装载和解释。
类库实际上是一组类文件。其中每个文件都有一个public类,以及任意数量的非public类。包的名称对应目录路径。
package语句必须是文件中的第一行非注释程序代码。在一个项目中,不可以有相同的两个包名,也就是说,包名不能和项目中其他的包名重复,这里不但包括自定义包名也包括项目所引用的类库的包名。
6.2 Java访问权限修饰词
对于一个类,其成员(包括成员变量和成员方法)能否被其他类所访问,取决于该成员的修饰词。在Java中,类成员的访问权限修饰词有四个:private,无(包访问权限),protected 和 public。
所有事物都具备访问权限控制,如果没写就是包访问控制权限。这种默认的访问权限没有关键字,有些时候表示为friendly。这就意味着当前的包中的所有其他类对那个成员都有访问权限,但对于这个包之外的所有类,这个成员是private的。
取得对某成员的访问权限的唯一途径:
使该成员成为public;
通过不加访问权限修饰符并将其他类放置于同一个包内的方式给成员赋予包访问控制权限;
继承而来的类可以访问public和protected类,private类不行,只有两个类处于同一个包时才能访问默认权限的;
提供访问器和变异器,get和set方法。
特别地,如果你不希望其他任何人对该类拥有访问权,你可以把所有的构造器都指定为private的,从而阻止任何人创建该类的对象。这个时候,该类的对象就只能在其static成员内部进行创建,这种情形有点像单例模式,例如像下面的例子那样:
class Test {
// private Constructor!
private Test() {}
// Allow creation via static method:
public static Test getTest() {
return new Test();
}
}
在上面所提到的四种修饰词中,除 protected 外都很好理解和掌握,在此略作简述:
public :被public修饰的类成员能被所有的类直接访问;
private:被private修饰的类成员只能在定义它的类中被访问,其他类都访问不到。特别地,我们一般建议将成员变量设为private的,并为外界提供 getter/setter 去对成员变量进行访问,这种做法充分体现了Java的封装思想;
包访问权限:包访问权限就是Java中的默认的权限,具有包访问权限的类成员只能被同一包中的类访问。
protected关键字
===========================================================
被protected修饰的成员对于本包和其子类可见。
实际上,protected的可见性在于两点:
基类的protected成员是包内可见的,并且对子类可见;
若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。
在碰到涉及protected成员的调用时,首先要确定出该protected成员来自何方,其可见性范围是什么,然后就可以判断出当前用法是否可行了。
===========================================================
//示例一package p1;
public class Father1 {
protected void f() {} // 父类Father1中的protected方法}package p1;
public class Son1 extends Father1 {}package p11;
public class Son11 extends Father1{}package p1;
public class Test1 {
public static void main(String[] args) {
Son1 son1 = new Son1();
son1.f(); // Compile OK ----(1) son1.clone(); // Compile Error ----(2) Son11 son = new Son11();
son11.f(); // Compile OK ----(3) son11.clone(); // Compile Error ----(4) }
}
对于上面的示例,首先看(1)(3),其中的f()方法从类Father1继承而来,其可见性是包p1及其子类Son1和Son11,而由于调用f()方法的类Test1所在的包也是p1,因此(1)(3)处编译通过。其次看(2)(4),其中的clone()方法的可见性是java.lang包及其所有子类,对于语句“son1.clone();”和“son11.clone();”,二者的clone()在类Son1、Son11中是可见的,但对Test1是不可见的,因此(1)(3)处编译不通过。
===========================================================
//示例二package p2;class MyObject2 {
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}package p22;
public class Test2 extends MyObject2 {
public static void main(String args[]) {
MyObject2 obj = new MyObject2();
obj.clone(); // Compile Error ----(1) Test2 tobj = new Test2();
tobj.clone(); // Complie OK ----(2) }
}
对于(1)而言,clone()方法来自于类MyObject2本身,因此其可见性为包p2及MyObject2的子类,虽然Test2是MyObject2的子类,但在Test2中不能访问基类MyObject2的protected方法clone(),因此编译不通过;对于(2)而言,由于在Test2中访问的是其本身实例的从基类MyObject2继承来的的clone(),因此编译通过。
===========================================================
//示例三package p3;class MyObject3 extends Test3 {
}package p33;
public class Test3 {
public static void main(String args[]) {
MyObject3 obj = new MyObject3();
obj.clone(); // Compile OK ------(1) }
}
对于(1)而言,clone()方法来自于类Test3,因此其可见性为包p33及其子类MyObject3,而(1)正是在p33的类Test3中调用,属于同一包,编译通过。
===========================================================
//示例四package p4;class MyObject4 extends Test4 {
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}package p44;
public class Test4 {
public static void main(String args[]) {
MyObject4 obj = new MyObject4();
obj.clone(); // Compile Error -----(1) }
}对于(1)而言,clone()方法来自于类MyObject4,因此其可见性为包p4及其子类(此处没有子类),而类Test4却在包p44中,因此不满足可见性,编译不通过。
==========================================================//示例五package p5;class MyObject5 {
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
public class Test5 {
public static void main(String[] args) throws CloneNotSupportedException {
MyObject5 obj = new MyObject5();
obj.clone(); // Compile OK ----(1) }
}对于(1)而言,clone()方法来自于类MyObject5,因此其可见性为包p5及其子类(此处没有子类),而类Test5也在包p5中,因此满足可见性,编译通过。
===========================================================//示例六package p6;class MyObject6 extends Test6{}
public class Test6 {
public static void main(String[] args) {
MyObject6 obj = new MyObject6();
obj.clone(); // Compile OK -------(1) }
}对于(1)而言,clone()方法来自于类Test6,因此其可见性为包p6及其子类MyObject6,而类Test6也在包p6中,因此满足可见性,编译通过。
===========================================================//示例七package p7;class MyObject7 extends Test7 {
public static void main(String[] args) {
Test7 test = new Test7();
test.clone(); // Compile Error ----- (1) }
}
public class Test7 {
}对于(1)而言,clone()方法来自于类Object,因此该clone()方法可见性为包java.lang及其子类Test7,由于类MyObject7不在此范围内,因此不满足可见性,编译不通过。
6.3 接口与实现
访问权限的控制常被称为是具体实现的隐藏。把数据和方法包装进类中,具体实现的隐藏,常共同被称作是封装。其结果是一个同时带有特征和行为的数据类型。
6.4 类的访问权限
每个编译单元(文件)都只能有一个public类,特殊情况下可以没有。
public类的名称必须完全与含有该编译单元的文件名一模一样。