Java言語を紹介する多くの書籍(『Javaプログラミング思想』を含む)は、protectedについて比較的簡単に紹介しており、基本的には一言だけです。すなわち:protected で修飾されたメンバーは、同じパッケージとそのサブクラスに対して可視である。この言い方は少し曖昧すぎて、しばしば皆さんに誤解を招きます。実際には、protected の可視性は次の2点にあります:

  • 基底クラスの protected メンバーは、パッケージ内で可視であり、サブクラスに対しても可視である;
  • サブクラスと基底クラスが同じパッケージ内にない場合、サブクラス内では、サブクラスのインスタンスは基底クラスから継承した protected メソッドにアクセスできますが、基底クラスのインスタンスの protected メソッドにはアクセスできません。

protected メソッドの可視性に関する以下のいくつかの例を通じて、protected キーワードをさらに理解できます。protected メンバーが関わる呼び出しに遭遇したとき、まずその protected メンバーがどこから来たのか、その可視性の範囲は何かを特定し、それから現在の使い方が可能かどうかを判断できます。以下の7つの例を見てください:

例 1

package p1; public class Father1 { protected void f() {} //親クラス Father1 の protected メソッド } package p1; public class Son1 extends Father1 {} package p11; public class Son11 extends Father1{} package p1; public class Test1 { public static void main(String[] args) { Son1 son1 = new Son1(); son1.f(); // Compile OK ----(1) son1.clone(); // Compile Error ----(2) Son11 son = new Son11(); son11.f(); // Compile OK ----(3) son11.clone(); // Compile Error ----(4) } }

上の例について、まず(1)(3)を見てください。その中のf()メソッドはクラスFather1から継承されたもので、その可視性はパッケージp1およびそのサブクラスSon1とSon11です。f()メソッドを呼び出すクラスTest1が属するパッケージもp1であるため、(1)(3)はコンパイルが通ります。次に(2)(4)を見てください。その中のclone()メソッドの可視性は java.lang パッケージとそのすべてのサブクラスです。文「son1.clone();」と「son11.clone();」について、両者のclone()はクラスSon1、Son11内では可視ですが、Test1からは不可視であるため、(2)(4)はコンパイルが通りません。

例 2

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 ----(1) Test2 tobj = new Test2(); tobj.clone(); // Complie OK ----(2) } }

(1)については、clone()メソッドはクラスMyObject2自体に由来するため、その可視性はパッケージp2およびMyObject2のサブクラスです。Test2はMyObject2のサブクラスですが、Test2内では基底クラスMyObject2のprotectedメソッドclone()にアクセスできないため、コンパイルは通りません。(2)については、Test2内でアクセスしているのは、自分自身のインスタンスが基底クラスMyObject2から継承したclone()であるため、コンパイルが通ります。

例 3

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 ------(1) } }

(1)については、clone()メソッドはクラスTest3に由来するため、その可視性はパッケージp33とそのサブクラスMyObject3です。(1)はまさにパッケージp33内のクラスTest3で呼び出されており、同じパッケージに属するため、コンパイルが通ります。

例 4

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 -----(1) } }

(1)については、clone()メソッドはクラスMyObject4に由来するため、その可視性はパッケージp4とそのサブクラス(ここではサブクラスはありません)です。しかし、クラスTest4はパッケージp44内にあるため、可視性を満たさず、コンパイルが通りません。

例 5

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 ----(1) } }

(1)については、clone()メソッドはクラスMyObject5に由来するため、その可視性はパッケージp5とそのサブクラス(ここではサブクラスはありません)です。クラスTest5もパッケージp5内にあるため、可視性を満たし、コンパイルが通ります。

例 6

package p6; class MyObject6 extends Test6{} public class Test6 { public static void main(String[] args) { MyObject6 obj = new MyObject6(); obj.clone(); // Compile OK -------(1) } }

(1)については、clone()メソッドはクラスTest6に由来するため、その可視性はパッケージp6とそのサブクラスMyObject6です。クラスTest6もパッケージp6内にあるため、可視性を満たし、コンパイルが通ります。

例 7

package p7; class MyObject7 extends Test7 { public static void main(String[] args) { Test7 test = new Test7(); test.clone(); // Compile Error ----- (1) } } public class Test7 { }

(1)については、clone()メソッドはクラスObjectに由来するため、このclone()メソッドの可視性はパッケージjava.langとそのサブクラスTest7です。クラスMyObject7はこの範囲内にないため、可視性を満たさず、コンパイルが通りません。

記事の出典:http://blog.csdn.net/justloveyou_/article/details/61672133