在 Java 中,所有事物都具有某种形式的访问权限控制。
访问权限的控制等级从最大到最小依次为:public,protected,包访问权限(无关键词)和 private。
public,protected 和 private 这几个 Java 访问权限修饰词在使用时,是置于类中每个成员(域或者方法)定义之前的。
取得对某成员的访问权的唯一途径是:
1). 使该成员成为 public。无论谁在哪里,都可以访问该成员;
2). 通过不加访问权限的修饰词并将其他类放置于同一包内的方式给成员赋予包访问权限,包内的其他类可以访问该成员;
3). 继承而来的类既可以访问 public 成员也可以访问 protected 成员。
4). 提供访问器和变异器方法,以读取和改变数值。
默认访问权限没有任何关键字,但通过是指包访问权限,这表示当前报中的所有其他类都对那个成员有访问权限,但是对于这个包之外的所有类,这个成员确是 private。
包访问权限将包内所有相关的类组合起来,以使它们彼此之间可以轻松地相互作用。
注意:如果两个类处于相同的目录下,并且没有给自己设定任何包名称,Java 会将这样的文件自动看作是隶属于该目录的默认包之中,于是这些文件互相之间有包访问权限。
下面的例子说明了这个问题:
- //类Cake和Pie处于同一目录下,没有明确的显示在任何包中
- class Pie {
- void f() {
- System.out.println("Pie.f()");
- }
- }
- class Cake {
- public static void main(String[] args) {
- Pie x = new Pie();
- x.f();
- }
- }
- //输出为Pie.f()
使用关键字 public,就意味着其后的成员声明对所有人可用,特别是使用类库的客户程序员也是如此。
关键字 private 表示出了包含该成员的类之外,其他任何类都无法访问这个成员。同一包内的其他类不可以访问这个类的 private 成员,因此这相当于自己隔离了自己。
private 关键字的这种作用有许多用途,比如,控制如何创建对象,阻止别人直接访问某个特定的构造器(或全部构造器)。看下面的例子:
- class Sundae {
- private Sundae() {}
- static Sundae makeASundae() {
- return new Sundae();
- }
- }
- public class IceCream {
- public static void main(String[] args) {
- Sundae x = Sundae.makeASundae();
- }
- }
这个例子里,我们可以通过调用 makeASundae() 方法来创建 Sundae 对象,但是不能通过构造器来创建。
这对于类中的 private 域同样适用。
但是要注意一点,不能因为在类中某个对象的引用是 private,就认为其他的对象无法拥有该对象的 public 引用。
如果创建了一个新包,并自另一个包继承类,那么唯一可以访问的成员就是源包的 public 成员。
有时,基类的创建者希望将某个特定成员的访问权限赋予派生类而非所有类,这就需要使用关键字 protected 来实现。
注意,protected 也提供包访问权限,即相同包内的其他类也可以访问此类的 protected 元素。
访问权限的控制通常被称为具体实现的隐藏。
把数据和方法包装进类中,以及具体实现的隐藏,常共同被称作是封装。
出于两个重要的原因,访问权限控制将权限的边界划在了数据类型的内部:
1. 要设定客户端程序员可以使用和不可以使用的界限。可以在结构中建立自己的内部机制,儿不必担心客户端程序员会偶然地将内部机制当做是他们使用的接口的一部分。
2. 接口和具体实现进行分离。
Java 中,访问权限修饰词也可以用于确定库中的哪些类对于该库的使用者是可用的。
修饰词必须放在关键字 class 之前。例如:
- public class Widget {......
- }或improt access.Widget;
要知道,类不可以是 private 的(如果类是 private 的,那么除了该类之外,其他任何类都不可以访问它),也不可以是 protected 的(其实一个内部类可以是 private 或 protected 的,但这是特例,后续文章中叙述),只可以是包访问权限或 public 的。
如果不希望其他人访问该类,可以把该类的所有构造器都指定为 private,阻止任何人创建该类的对象。但这也有例外,这种做法不能阻止你在该类的 static 成员内部创建该类。我们来看下边的例子:
- class Soup1 {
- private Soup1() {}
- public static Soup1 makeSoup() { //使用静态方法创建对象
- return new Soup1();
- }
- }
- class Soup2 {
- private Soup2() {}
- private static Soup2 ps1 = new Soup2(); //使用单例模式创建对象
- public static Soup2 access() {
- return ps1;
- }
- public void f() {}
- }
- public class Lunch {
- void testPrivate() {
- //Soup1 soup = new Soup1; 不能执行
- }
- void testSingleton() {
- Soup2.access().f();
- }
- }
我们可以看到,Soup1 和 Soup2 类的构造器都是 private 的,谁也无法直接使用构造器来创建该类的对象了。但是我们也可以使用这两个类:在 Soup1 中创建一个 static 方法,在这个方法中使用构造函数创建一个 Soup1 对象并返回它的引用;Soup2 的创建用了设计模式中的单例模式,只能创建它的一个对象。Soup2 类的对象是作为 Soup2 的一个 static private 成员而创建的,所以有且仅有一个,而且除非是通过 public 方法 access(),否则是无法访问到它的。
此外,一些限制也值得注意:
1. 每个编译单元都只能有一个 public 类。
2.public 类的名称必须完全与含有给编译单元的文件名相匹配,包括大小写。
3. 如果编译单元内没有带 public 的类,这时可以对文件随意命名。
来源: http://www.cnblogs.com/songwenlong/p/6147825.html