@lemonguge
2015-06-23T02:25:00.000000Z
字数 3018
阅读 368
JAVA
访问控制(或隐藏具体实现)与“最初的实现并不恰当”有关。
所有优秀的作者,包括那些编写软件的程序员,都清楚其著作的某些部分直至重新创作的时候才变得完美,有时甚至要反复重写多次。这正是重构的原动力之一,重构即重写代码,以使得它更可读、更易理解,并因此而更具有可维护性。
通常会有一些客户端程序员使用我们的代码,他们会希望我们的代码在某些方面保持不变。由此而产生了在面向对象设计中需要考虑的一个基本问题:“如何把变动的事物与保持不变的事物区分开来”。
为了解决这个问题,Java提供了访问权限修饰词,以提供类库开发人员向客户端程序员指明哪些是可用的,哪些是不可用的。访问权限控制的等级,从最大权限到最小权限依次为:public、protected、包访问权限(没有关键字)和private。而访问权限修饰词会因类存在于一个相同的包,还是存在于单独的包而受到影响。
访问权限的控制常被称为是具体实现的隐藏。把数据和方法包装进类中,以及具体实现的隐藏,并对外提供公共的访问方式,常共同被称作是封装。
包内包含了一组类,它们在单一的名字空间之下被组织在一起。
我们使用一个类的一种方式是使用其全名来指定,但这会让程序变得冗长,因此我们会转而使用import关键字,为我们想使用的类,可以在import语句中命名该类。可以使用单个类导入的形式来防止冲突,可是一旦使用了有冲突名字,必须使用指定全名的方式。
// 全名指定java.util.ArrayList list = new java.util.ArrayList();等价于// 导入想使用的类import java.util.ArrayList;...ArrayList list = new ArrayList();// 导入一个包中的所有类:import java.util.*;
当编写一个Java源代码文件时,此文件通常被称为编译单位(有时候也称为转译单位),每个编译单元都是必须有一个后缀名.java,而在每个编译单位只能有一个public类且必须与文件名称相同,否则编译器会提示The public type xxx must be defined in its own file。如果在该编译单元之中还有额外的类的话,那么在包外的世界是无法看见这些类的,这是因为它们不是public类,而且它们主要是用来为public类提供支持的。
类库实际上是一组类文件。其中每一个.java文件都有一个public类,以及任意数量的非public类。因此每一个.java文件(编译后至少有一个.class文件)都有一个构件(构件包括.java文件和.class文件)。如果希望这些构件从属于同一个群组,就可以使用package,必须注意的是,package语句必须是.java文件中除注释以外的第一句程序代码!
环境变量CLASSPATH包含一个或多个目录,用作查找.class文件的根目录。从根目录开始,java解释器获取包名称并将每个句号“.”替换成反斜杠(目录的反斜杠),以从CLASSPATH根中产生一个路径名称,反斜杠取决于操作系统。得到的路径会与CLASSPATH中的各个不同项相连接,解释器就在这些目录中查找与你所要创建的类名称相关的.class文件。在配置CLASSPATH时,我们会常常先配置“CLASSPATH=.;D:\java\..;C:\..”,这里最开始的.;表示当前目录。
为了避免包名发生冲突,建议使用我们的域名的反顺序小写来定义包名。务必记住,无论何时创建包,都已经在给定包的名称的时候隐含了目录结构。
public、protected、包访问权限(没有关键字)和private这四种访问权限都是可以置于类中的每个成员(成员变量和成员函数)的定义前。
| 访问权限 | 同一个类 | 同一个包 | 不同包的子类 | 不同包的非子类 |
|---|---|---|---|---|
| public | OK | OK | OK | OK |
| protected | OK | OK | OK | |
| default | OK | OK | ||
| private | OK |
通过上图,我们可以了解到protected访问权限仅次于public,值得注意的是,protected这个访问权限是针对与基类而言,不同的包中的子类可以访问到这个protected方法,子类虽然继承了这个方法,但这个方法在子类中的权限如同private,即与该子类在同一包的其他类不能访问到这个方法!
// Cookie类在access.cookie2包中package access.cookie2;public class Cookie {public Cookie() {System.out.println("Cookie constructor");}protected void bite() {System.out.println("bite");}}// ChocolateChip2类在access包中,继承自Cookie类package access;import access.cookie2.*;public class ChocolateChip2 extends Cookie {public ChocolateChip2() {System.out.println("ChocolateChip2 constructor");}public void chomp() {bite(); // Protected method}public static void main(String[] args) {ChocolateChip2 x = new ChocolateChip2();x.chomp();x.bite();}} /* Output:Cookie constructorChocolateChip2 constructorbitebite*///:~// TestChocolateChip2类与ChocolateChip2类同样在access包中package access;public class TestChocolateChip2 {public static void main(String[] args) {ChocolateChip2 x = new ChocolateChip2();x.chomp();// ! x.bite();//编译器报错!}} /* Output:Cookie constructorChocolateChip2 constructorbite*///:~
ChocolateChip2类虽然继承自Cookie类,但是bite()方法仍是在Cookie的方法区中,ChocolateChip2只是通过一个super指向父类在方法区的位置。当在TestChocolateChip2中想调用bite()方法时,Cookie类protected访问权限不会允许,所以会在编译器提示“The method bite() from the type Cookie is not visible”错误。
对于类的访问权限,仅有两个选择,包访问权限或
public。
类既不可以是private的,这个的访问权限会导致除了该类之外,其他任何类都不可以访问它,也就失去了创建这个类的意义;也不可以是protected。如果不希望其他人对该类有访问权限(不允许任何人创建该类的对象),可以把所有的构造器声明为private(如同之前介绍的enum),我们可以在该类的static成员内部创建(由于不能创建该类的对象,仅能通过类名访问静态成员)。