[关闭]
@lemonguge 2015-06-23T02:25:00.000000Z 字数 3018 阅读 368

访问权限控制

JAVA


访问控制(或隐藏具体实现)与“最初的实现并不恰当”有关。

所有优秀的作者,包括那些编写软件的程序员,都清楚其著作的某些部分直至重新创作的时候才变得完美,有时甚至要反复重写多次。这正是重构的原动力之一,重构即重写代码,以使得它更可读、更易理解,并因此而更具有可维护性。

通常会有一些客户端程序员使用我们的代码,他们会希望我们的代码在某些方面保持不变。由此而产生了在面向对象设计中需要考虑的一个基本问题:“如何把变动的事物与保持不变的事物区分开来”。

为了解决这个问题,Java提供了访问权限修饰词,以提供类库开发人员向客户端程序员指明哪些是可用的,哪些是不可用的。访问权限控制的等级,从最大权限到最小权限依次为:publicprotected、包访问权限(没有关键字)和private。而访问权限修饰词会因类存在于一个相同的包,还是存在于单独的包而受到影响。

访问权限的控制常被称为是具体实现的隐藏。把数据和方法包装进类中,以及具体实现的隐藏,并对外提供公共的访问方式,常共同被称作是封装


包:库单位

包内包含了一组类,它们在单一的名字空间之下被组织在一起。

我们使用一个类的一种方式是使用其全名来指定,但这会让程序变得冗长,因此我们会转而使用import关键字,为我们想使用的类,可以在import语句中命名该类。可以使用单个类导入的形式来防止冲突,可是一旦使用了有冲突名字,必须使用指定全名的方式。

  1. // 全名指定
  2. java.util.ArrayList list = new java.util.ArrayList();
  3. 等价于
  4. // 导入想使用的类
  5. import java.util.ArrayList;
  6. ...
  7. ArrayList list = new ArrayList();
  8. // 导入一个包中的所有类:
  9. 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:\..”,这里最开始的.;表示当前目录。

为了避免包名发生冲突,建议使用我们的域名的反顺序小写来定义包名。务必记住,无论何时创建包,都已经在给定包的名称的时候隐含了目录结构。


成员的访问权限

publicprotected、包访问权限(没有关键字)和private这四种访问权限都是可以置于类中的每个成员(成员变量和成员函数)的定义前。

访问权限 同一个类 同一个包 不同包的子类 不同包的非子类
public OK OK OK OK
protected OK OK OK
default OK OK
private OK

通过上图,我们可以了解到protected访问权限仅次于public,值得注意的是,protected这个访问权限是针对与基类而言,不同的包中的子类可以访问到这个protected方法,子类虽然继承了这个方法,但这个方法在子类中的权限如同private,即与该子类在同一包的其他类不能访问到这个方法!

  1. // Cookie类在access.cookie2包中
  2. package access.cookie2;
  3. public class Cookie {
  4. public Cookie() {
  5. System.out.println("Cookie constructor");
  6. }
  7. protected void bite() {
  8. System.out.println("bite");
  9. }
  10. }
  11. // ChocolateChip2类在access包中,继承自Cookie类
  12. package access;
  13. import access.cookie2.*;
  14. public class ChocolateChip2 extends Cookie {
  15. public ChocolateChip2() {
  16. System.out.println("ChocolateChip2 constructor");
  17. }
  18. public void chomp() {
  19. bite(); // Protected method
  20. }
  21. public static void main(String[] args) {
  22. ChocolateChip2 x = new ChocolateChip2();
  23. x.chomp();
  24. x.bite();
  25. }
  26. } /* Output:
  27. Cookie constructor
  28. ChocolateChip2 constructor
  29. bite
  30. bite
  31. *///:~
  32. // TestChocolateChip2类与ChocolateChip2类同样在access包中
  33. package access;
  34. public class TestChocolateChip2 {
  35. public static void main(String[] args) {
  36. ChocolateChip2 x = new ChocolateChip2();
  37. x.chomp();
  38. // ! x.bite();//编译器报错!
  39. }
  40. } /* Output:
  41. Cookie constructor
  42. ChocolateChip2 constructor
  43. bite
  44. *///:~

ChocolateChip2类虽然继承自Cookie类,但是bite()方法仍是在Cookie的方法区中,ChocolateChip2只是通过一个super指向父类在方法区的位置。当在TestChocolateChip2中想调用bite()方法时,Cookieprotected访问权限不会允许,所以会在编译器提示“The method bite() from the type Cookie is not visible”错误。


类的访问权限

对于类的访问权限,仅有两个选择,包访问权限或public

类既不可以是private的,这个的访问权限会导致除了该类之外,其他任何类都不可以访问它,也就失去了创建这个类的意义;也不可以是protected。如果不希望其他人对该类有访问权限(不允许任何人创建该类的对象),可以把所有的构造器声明为private(如同之前介绍的enum),我们可以在该类的static成员内部创建(由于不能创建该类的对象,仅能通过类名访问静态成员)。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注