摘要:
# 在一個類別的內部,其成員(包括成員變數和成員方法)能否被其他類別所訪問,取決於該成員的修飾詞;而一個類別能否被其他類別所訪問,取決於該類別的修飾詞。 Java的類別成員存取權限修飾詞有四個類別:private,無(預設情況下,套件存取權限),protected 和 public,而其中只有套件存取權限和public才能修飾一個類別(內部類別除外)。特別地,許多的介紹Java的書籍對protected介紹的比較籠統,常常會對大家造成誤解。因此,本文重點揭示了 protected 關鍵字的內涵和用法,並介紹了一些其他的修飾符。
版權聲明:
本文原創作者:書呆子Rico
作者部落格網址:http://www.php.cn/
關於包的使用,我們只需注意一點:在一個專案中,不可以有相同的兩個包名,也就是說,我們的套件名稱不能和專案中其他的套件名稱重複,這裡不但包含自訂套件名稱也包含專案所引用的類別庫的套件名稱。 看下面範例:
package java.lang;public class MyObject { public static void main(String[] args) throws CloneNotSupportedException { Object o = new Object(); System.out.println(o.hashCode()); } }
我們給自己的程式的套件名稱是 java.lang,事實上,我們知道 java.lang 是JDK使用的套件名稱。 程式可以正常編譯,但當我們執行程式時會有套件衝突警告並拋出「java.lang.SecurityException: Prohibited package name: java.lang」 例外,如下圖所示。
句## 句
## 句。 ,那麼它必須是文件中除二. Java存取權限概述private,無(預設情況下,套件存取權限),protected 和 public。 其權限控制如下表所示:
成員,兩者要區分開),其存取權限修飾詞僅有public 和「無」(即套件存取權)兩種,而沒有private 和protected(有一個特例,只有內部類別可以是private或protected的,關於內部類別進一步了解請見我的部落格《Java 內部類別綜述》)。 因此,對於非內部類,我們只能賦予其套件存取權限或是 public 。 如果你不希望其他任何人對該類別擁有存取權,你可以把所有的建構器都指定為 private,從而阻止任何人創建該類別的物件
。這時候,該類別的物件只能在其static 成員內部進行創建,這種情況有點像單例模式
,例如像下面的範例:class Test { // private Constructor! private Test() {} // Allow creation via static method: public static Test getTest() { return new Test(); } }
private:被public修饰的类成员只能在定义它的类中被访问,其他类都访问不到。特别地,我们一般建议将成员变量设为private的,并为外界提供 getter/setter 去对成员变量进行访问,这种做法充分体现了Java面向对象的四大特性(封装,多态,继承,抽象)中的封装思想;
包访问权限:包访问权限就是Java中的默认的权限,具有包访问权限的类成员只能被同一包中的类访问。
由于 protected 关键字的真正内涵不太容易理解,我们将在下一节专门介绍 protected 关键字。
很多的有关介绍Java语言的书籍 (包括《Java编程思想》),都对protected介绍的比较的简单,基本都是一句话,就是:被protected修饰的成员对于本包和其子类可见。这种说法有点太过含糊,常常会对大家造成误解。对于protected的成员,要分子类和超类是否在同一个包中两种情况看待,现以 protected方法的调用为例进行说明,protected的成员变量类似。
实质上,protected方法的调用是否合法(编译是否通过)关键是要看被调用的protected方法从根源上看所在的类对应的包与调用代码所在的类对应的包是否相同,若相同,则合法;否则,不合法。当然,无论如何,子类是可以访问继承而来的属于它自己的受保护方法的。
我们可以看下面例子进行了解。
1). 第一种情形:子类与基类不在同一个包中
//示例一package p1;public class Father1 { protected void f() {} // 父类Father1中的protected方法}package p1; public class Son1 extends Father {}package p11; public class Son11 extends Father{}package p1; public class Test1 { public static void main(String[] args) { Son1 son1 = new Son1(); son1.f(); // Compile OK,protected方法f()来自于Father1类,与 Test1类 在同一包p1中 son1.clone(); // Compile Error,protected方法clone()来自于Object类,与 Test1类不在同一包中 Son11 son = new Son11(); son11.f(); // Compile OK,虽然Son11类在包p11中,但protected方法f()来自于Father1类,与 Test1类在同一包p1中 son11.clone(); // Compile Error,protected方法clone()来自于Object类,与 Test1类不在同一包中 } }
在上面的示例中,类Father1、Son1 和 Test1 在同一个包p1下,类Son11在包p11下。但是我们知道,无论Son1类还是Son11类,它们的protected方法f()在根源上都来自于p1包中的类Father1,而由于Test1也在p1包中,因此f()方法对Test1类可见,编译通过。但由于Son1类和Son11类中的clone()方法在根源上均来自于java.lang包下的类Object,与 Test1类不在同一包中,因此clone()方法对Test1类不可见,编译不通过。
//示例二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,protected方法clone()来自于MyObject2类,与 Test2类 不在同一包p1中 Test2 tobj = new Test2(); tobj.clone();// Complie OK,虽然 protected方法clone()来自于MyObject2类,与 Test2类 不在同一包p1中,但Test2类作为MyObject2类的子类,是可以访问继承而来的属于它自己的受保护方法的。 } }
在上面的示例中,类MyObject2 和 类Test2 分别在包 p2 和 p22 下。因此,在类Test2中通过MyObject2的引用调用MyObject2的protected方法clone()时,由于类MyObject2 和 类Test2 不在同一包中而编译不通过。但是我们知道,虽然 类Test2 的protected方法clone()在根源上也来源于 类MyObject2,但是Test2类作为MyObject2类的子类,是可以访问继承而来的属于它自己的受保护方法的。
//示例三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,protected方法clone()来自于Test3类,而现在正是在Test3类中访问该方法 } }
在上面的示例中,类MyObject3 和 类Test3 分别在包 p3 和 p33 下。但是由于 MyObject3类的protected方法clone()在根源上来自于类Test3中,而现在正是在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,protected方法clone()来自于MyObject4类,而Test4类与MyObject4类不在同一个包中 } }
该示例与示例三很类似,唯一不同的是 类MyObject4 重写了从 类Test4 中继承过来的protected方法clone()。这样,MyObject4 的 protected方法clone()在根源上来自于类本身而非Test4类。而类MyObject4 和 类Test4 又不在同一包下,因此编译不通过。
2). 第二种情形:子类与基类在同一个包中
//示例五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,protected方法clone()来自于MyObject5类,而Test5类与MyObject5类又在同一个包中 } }
该示例与示例四很类似,唯一不同的是 类MyObject5 与 类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 } }
在本示例中,由于类MyObject中的protected方法clone()从根源上来自于Test6类,而现在正是在 Test6 中调用protected方法clone(),因此编译通过。
//示例七package p7; class MyObject7 extends Test7 { public static void main(String[] args) { Test7 test = new Test7(); test.clone(); // Compile Error. } }public class Test {}
在本示例中,虽然类MyObject7与Test7类在同一个包p7中,但是由于 类Test7 的protected方法clone()从根源上来自于 java.lang.Object类,而其又与MyObject7不在同一个包中,因此编译不通过。
static:修饰变量和内部类(不能修饰常规类),其中所修饰变量称为类变量或静态变量。静态变量是和类存在一起的,每个实例共享这个静态变量,在类加载时初始化。
final:被宣告為final的變數必須在宣告時給定初始值(當然,空白 final 情形除外),而且被修飾的變數不能修改值。當修飾類別時,該類別不能衍生出子類別;修飾方法時,該方法不能被子類別覆蓋。若讀者想對 final 有更深刻的了解,請移步我的博文 《Java 繼承、多態與類別的複用》。
abstract:修飾類別與方法。當修飾類別時,該類別不能建立物件;修飾方法時,為抽象方法。類別只要有一個abstract方法,類別就必須定義為abstract,但abstract類別不一定要有abstract方法不可。
在一個類別的內部,其成員(包括成員變數和成員方法)能否被其他類別所訪問,取決於該成員的修飾詞;而一個類別能否被其他類所訪問,取決於該類的修飾詞。 Java的類別成員存取權限修飾詞有四個類別:private,無(預設情況下,套件存取權限),protected 和 public,而其中只有套件存取權限和public才能修飾一個類別(內部類別除外)。特別地,本文重點揭示了 protected 關鍵字的內涵和用法,並介紹了一些其他的修飾符。
在綜述本章的過程中,我們涉及到了很多知識點,其中有一些我們已經在其他博文中專門提到過,因此沒有作更多詳細的闡述,這裡給出對應的連結:
以上是Java存取權限控制-帶你詳細了解protected關鍵字(圖)的詳細內容。更多資訊請關注PHP中文網其他相關文章!