您的位置:首页 > 编程语言 > Java开发

Java 访问权限修饰词

2016-06-04 00:00 197 查看
原文摘自《Thinking in Java》

publicprotectedprivate 这几个 Java 访问权限修饰词在使用时,是置于类中每个成员定义之前——无论它是一个域还是一个方法。每个访问权限修饰词仅控制它所修饰的特定定义的访问权。

如果不提供任何访问权限修饰词,则意味着它是“包访问权限”。因此,无论如何,所有事物都具有某种形式的访问权限控制。

#包访问权限

默认访问权限没有任何关建字,但通常是指包访问权限(有时也表现成 friendly)。这就意味着当前的包中的所有其他类对那个成员都有访问权限,但对于这个包以外的所有类,这个成员却是 private 。由于一个编译单元(即一个文件)。只能隶属于一个包,所以经由包访问权限,处于同一个编译单元中的所有类彼此之间都是可以自动访问的。

包访问权限允许将包内所有相关的类组合起来,以使它们彼此之间可以轻松地相互作用。你“拥有”了该包内的程序代码。“只有你拥有了程序代码才可以访问你所拥有的其他程序代码”,这是合理的。应该说,包访问权限为把类群聚在一个包中的做法提供了意义和理由。在许多语言中,在文件内组织定义的方式是任意的,但在 java 中则要强制你以一种合理的方式对他们加以组织。另外,你可能还要排除这样的类——它们不应该访问在当前包中所定义的类。

类控制着哪些代码有访问自己的成员。其他包内的类不能刚一上来就说:“嗨,我是 Bob 的朋友。”并且还想看到 Bob 的 protected 、包访问权限和 private 成员。取得对某成员的访问权唯一途径是:

使该成员成为 public 。于是,无论是谁,无论在哪里,都可以访问该成员。

通过不加访问权限修饰词并将其他类放置于同一个包内的方式给成员赋予包访问权限。于是包内的其他类也就可以访问该成员了。

继承而来的类即可以访问 public 成员也可以访问 protected 成员(但访问 private 成员就不行) 。只有两个类都处于同一个包内时,它才可以访问包访问权限的成员。

提供访问器(accessor)和变异器(mutator)方法(也称作 get/set 方法),以读取和改变数值。

#public:接口访问权限

使用关键字 public ,就意味着 public 之后紧跟着的成员声明自己对每个人都是可用的,尤其是使用类库的客户程序更是如此。假设定义了一个包含下面编译单元的 dessert 包:

//:access/dessert/Cookie.java
//Creates a library.
package access.desert;
public class Cookie {
public Cookie(){
System.out.println("Cookie constructor");
}\
void bite(){(System.out.println("bite");}
}///:~

记住,Cookie.java 文件必须位于名为 dessert 的子目录之中,该子目录在 access 下,而 c05 则必须位于 CLASSPATH 指定的众多路径的其中之一的下边。不要错误的认为 Java 总是将当前目录视作查找行为的起点之一。如果你的 CLASSPATH 之中缺少一个 “ . ”作为路径之一的话,Java 就不会查找那里。

现在如果创建了一个使用 Cookie 的程序:

//:access/Dinner.java
//User the library.
import access.dessert.*;

public class Diner{
public static void main (String[] args){
Cookie x = new Cookie();
//! x.bite();//Can't access
}
}/* Output:
Cookie constructor
*///:~

就可以创建一个 Cookie 对象,因为它的构造器是 public 而且类也是 public 的。但是,由于 bite() 只向在 dessert 包中的类提供访问权,所以 bite() 成员在 Dinner.java 只中是无法访问的,因此编译器也禁止你使用它。

默认包

令人吃惊的 是,下面的程序代码虽然看上去破坏了上述规则,但它仍可以编译:

//:access/Cake.java
//Acesses a class in a separate compilation unit.

class Cake {
public static void main (String[] args){
Pie x = new Pie();
x.f();
}
}/*Output:
Pie.f()
*///:~

在第二个处于相同目录的文件中:

//:access/Pie.java
//The other class.
class Pie {
`void f(){System.out println("Pie.f()");}
}///:~

最初或许认为这两个文件毫不相关,但 Cake 却可以创建一个 Pie 对象并调用它的 f() 方法!(记住,为了使文件可以被编译,在你的 CLASSPATH 之中一定要有“ . ”。)通常会认为 Pie 和 f() 享有包访问权限,因而是不可以为 Cake 所用的。他们的。他们的确享有包访问权限,但这只是部分正确的。 Cake.java 可以访问它们的原因是因为他们处于相同的目录并且没有给自己设定任何包名称。Java 将这样的文件自动看作是隶属于该目录的默认包之中,于是他们为该目录中所有其他的文件都提供了包访问权限。

#private:你无法访问

关键字 private 的意思是,除了包含该成员的类之外,其他任何类都无法访问这个成员。由于处于同一包内的其他类是不可以访问 private 成员的,因此,这等于说是自己隔离了自己。从另一方面说,让许多人共同合作来创建一个包是不大可能的,为此 private 就允许你随意改变该成员,而不必考虑这样做是否会影响到包内其他类。

默认的包访问权限通常已经提供了充足的隐藏措施。请记住, 使用类的客户端程序员是无法访问包访问权限成员的。这样做很好,因为默认访问权限是一种我们常用的权限,同时也是一种在忘记添加任何访问权限控制时能够自动得到的权限。因此,通常考虑的是,哪些成员是想要明确公开给客户端程序员使用的,从而将他们声明为 public ,而在最初,你可能不会认为自己经常会需要使用关键字 private,因为没有它,照样可以工作。然而,事实很快就会证明,对 private 的使用是多么重要,在多线程环境下更是如此。

此处有一个使用 private 的示例。

//:access/IceCream.java
//Demonstrates "private" keyword.

class Sundae(){
private Sundae(){}
static Sundae makeASundae(){
return new Sundae();
}
}

public class IceCream {
public static void main(String[] args){
//! Sundae x = new Sundae();
Sundae x = Sundae.makeASundae();
}
}///:~

这是一个说明 private 终有其用武之地的示例:可能想控制如何创建对象,并阻止别人直接访问某个特定的构造器(或全部构造器)。在上面例子中,不能通过构造器来创建 Sundae 对象,而必须调用 makeASundae() 方法来达到此目的。

任何可以肯定只是该类的一个“助手”方法的方法,都可以把它指定为 private ,以确保不会在包内的其他地方误用到它,于是也就防止了你会去改变或删除这个方法。将方法指定为 private 确保了你拥有这种选择权。

这对于类中的 private域同样适用。除非必须公开底层实现细目(这种情况很少见),否则,就应该将所有域指定为 private 。然而,不能因为在类中某个对象的引用是 private ,就认为其他对象无法拥有该对象的 public 引用。

#protected:继承访问权限

关键字 protected 处理的是继承的概念,通过继承可以利用一个现有类——我们将其称为基类,然后将新成员添加到该现有类中而不必碰该现有类。还可以改变该类的现有成员行为。为了从现有类中继承,需要声明新类 extend (扩展)了一个现有类,就像这样:

class Foo extend Bar {

类定义中其他部分看起来都是一样的。

如果创建了一个新包,并自另一个包中继承类,那么唯一可以访问的成员就是源包的 public 成员。(当然,如果在同一个包内执行继承工作,就可以操纵所有的拥有包访问权限的成员。)有时,基类的创建者会希望有某个特定成员,把对它的访问权限赋予派生类,而不是所有类。这就需要 protected 来完成这一工作。 protected 也提供包访问权限,也就是说,相同包内的其他类可以访问 protected 元素。

回顾一下先前的例子 Cookie.java 就可以得知下面的类是不是调用拥有包访问权限的成员 bote() 的:

//:access/ChocolateChip.java
//Can't use package-access member from another package.
import access.dessert.*;

public class ChocolateChip extend Cookie{
public ChocolateChip () {
System.outzAX-`
``.println("ChocolateChip constructor");
}
public void chomp(){
//!bite();//Can't access bite
}
public static void main(String[] args){
ChocolateChip x =new ChocolateChip();
x.chomp();
}
}/*Output:
Cookie constrctor
Choco;ateChip constructor
*///:~

有关继承技术的一个很有趣的事情是,如果类 Cookie 中存在一个方法 bite() 的话,那么该方法同时也存在一个从 Cookie 继承而来的类中。但是由于 bite 有包访问权限而且它位于另一个包内,所以我们在这个包内是无法使用它的。当然,也可以把它指定为 public ,但是这样做所有人都有了访问权限,而且这很可能并不是你所希望的那样。如果我们将类 Cookie 像这样加以更改:

//:access/cookie2/cookie.java
package access.cookie2:

public class Cookie2{
public Cookie(){
System.out.println("Cookie constructor");
}
proteced void bite(){
System.out.println("bite");
}
}///:~

现在 bite() 对于所有继承自 Cookie 的类而言,也是可以使用的。

//:access/cookie2/Cookie.java
package 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 = mew ChocolateChip2();
x.chomp();
}
}/*Output:
Cookie constructor
ChocolateChip2 constructor
bite
*///:~

注意,尽管 bite() 也具有包访问权限,但依旧不是 public 的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: