protected、本当に理解しましたか?


Javaのアクセス制御修飾子は4つのレベルがありますが、protectedが最も複雑です.皆さんに聞くと、protected修飾子の役割は、「サブクラスと同パッケージでこのメンバーにアクセスできる」と言われますが、もちろん自分のクラスでも可能ですが、本当に理解していますか?信じないで、まず以下の実例を見て、あなたもそう思っているかどうかを見てみましょう(その中で注釈が落ちているのはコンパイルできないので、みんなはこれらのコードをeclipseの中に置いてから見たほうがいいです.そうしないと、あなたは気絶します^^):
package pk1.a;
public class Base {
	protected int i = 1;
	protected void protect() {
		System.out.println("Base::protect");
	}
}

package pk1.a;
import pk1.b.Sub;
public class SubSub extends Sub {
	void g() {
		Sub s = new SubSub();
		//!! s.protect();//  2.c.i
		System.out.println(s.i);//  2.c.ii
	}
}

package pk1.b;
import pk1.a.Base;
public class Sub extends Base {
	private void prt() {}
	protected void protect() {
		System.out.println("Base::protect");
	}
	void f() {
		//  2.a
		this.protect();
		this.i = 2;

		//  2.b
		Base a2 = new Sub();
		//!! a2.protect();
		//!! System.out.println(a2.i);

		//  1
		Sub b = new Sub();
		b.protect();
		b.i = 1;
		b.prt();
	}
}

package pk1.b;
public class SubSub extends Sub {
	void g() {
		Sub s = new SubSub();
		s.protect();//  2.c.i
		//!! System.out.println(s.i);//  2.c.ii
	}
}

package pk1.c;
import pk1.a.Base;
import pk1.b.Sub;
public class SubSub extends Sub {
	void g() {
		this.protect();//  2.a

		//  2.b
		Base b = new SubSub();
		//!! b.protect();
		//!! System.out.println(b.i);

		//  2.b
		Sub s = new SubSub();
		//!! s.protect();
		//!! System.out.println(s.i);

	}
}

 
package pk2.a;
public class Base {
	protected int i = 1;

	protected void protect() {
		System.out.println("Base::protect");
	}
}

package pk2.a;
import pk2.b.Sub;
public class Other {
	void g() {
		//  3.a
		Base b = new Sub();
		b.protect();
		System.out.println(b.i);

		//  3.b.ii
		Sub s = new Sub();
		s.protect();
		System.out.println(s.i);
	}
}

package pk2.b;
import pk2.a.Base;
public class Other {
	void g() {
		//  3.a
		Base b = new Sub();
		//!! b.protect();
		//!! System.out.println(b.i);

		//  3.b.ii
		Sub s = new Sub();
		//!! s.protect();
		//!! System.out.println(s.i);
	}
}

package pk2.b;
import pk2.a.Base;
public class Sub extends Base {}

 
package pk3.a;
import pk3.b.Sub;
public class Base {
	protected int i = 1;
	protected void protect() {
		System.out.println("Base::protect");
	}
	
	static protected int i_s = 1;
	static protected void protect_s() {
		System.out.println("Static:Base::protect");
	}
	
	void f() {
		//!! Sub.i_s = 2; //  3.b.i
		Sub.protect_s();//  3.b.ii
	}
}

package pk3.a;
import pk3.b.Sub;
public class Other {
	void g() {
		Sub s = new Sub();
		//!! s.protect();//  3.b.i
		System.out.println(s.i);//  3.b.ii
	}

	void f() {

		//!! Sub.i_s = 2; //  3.b.i
		Sub.protect_s();//  3.b.ii

		Base.i_s = 2;//  3.a
		Base.protect_s();//  3.a

	}
}

package pk3.b;
import pk3.a.Base;
public class Other {
	void f() {
		Sub.i_s = 2;//  3.b.i
		//!! Sub.protect1();//  3.b.ii
		
		//!! Base.i1 = 2;//  3.a
		//!! Base.protect1();//  3.a
	}
}

package pk3.b;
import pk3.a.Base;
public class Sub extends Base {
	protected void protect() {
		System.out.println("Base::protect");
	}
	static protected int i_s = 2;

	void f() {
		
		/*
		 *                         protected  
		 *   ,               ,             
		 * 
		 *  ,                   
		 */
		System.out.println(Sub.i_s);//2
		Sub.protect_s();
	
		System.out.println(Base.i_s);//1
		Base.protect_s();
	}
}

 
もしあなたがここを見て、考えがプログラムと一致しているならば、あなたが理解したことを説明して、もし理解しないならば、私の理解を見てみましょう:
 
ルールを定義する前に、私はここで3つのクラスを約束しました.1つはBaseクラスで、1つはBaseクラスのサブクラスSubクラスで、1つはSubクラスのサブクラスSubSubSubSubSubSubクラスで、もう1つはOtherクラスで、Base、Sub、SubSubSubSubとは関係を継承していません.Baseにprotectedメソッドと属性があると仮定して、YYと呼びましょう.
 
protectedルールを理解するには、まずアクセスとは何かを明らかにします.ここで説明するアクセスには2つあります.
一、クラスの中で“XXX x=new XXX();x.YYY;”の形式でアクセスします(この形式を“外部アクセス”と呼ぶことができて、このようなアクセス形式は自分とサブクラスの外に適用することができるほか、その他のクラスの中でアクセスすることができて、その中のXXXは定義のタイプを表して、ここでBaseとSub、SubSubSubSubSub、YYYは方法あるいは属性です);
二、これです.YYY形式でアクセスする(この形式を「内部アクセス」と呼んでもいいでしょうが、このアクセス形式は自分のクラスやサブクラスにしか適用できません).
 
protectedメソッドとプロパティがアクセスできる場所は3つあります.
1.自分の類Baseの中で:上の“XXX x=new XXX();x.YYY;”「this.YYY」の2つのアクセス形式でアクセスできる、独自に定義されたportectedメソッドまたはプロパティ.
2.2つ目はサブクラスSub、SubSubSubSubの3つのアクセス方法に分けられます.
a.Sub、SubSubSubSubの「this.YYY」の内部アクセス形式:この形式では、親ベースのprotectedメソッドと属性を書き換えたり再定義したりしたかどうかにかかわらず、サブクラスSub、SubSubSubは必ずアクセスできます.
b.Sub、SubSubSubSubで「Basex=new XXX();x.YYY;」外部アクセス形式:この形式は必ずしもアクセスできるものではありません.これは、親ベースがサブクラスSub、SubSubSubSubと同じパッケージにあるかどうかにかかっています(これらのprotedtedメソッドを書き換えたり再定義したりするかどうかは属性とは関係ありません).
c.SubSubSubで「Subx=new XXX();x.YYY;」外部アクセス形式:このアクセス形式がアクセスできるかどうかは、SubがBaseの属性と方法を書き換えたり再定義したりしたかどうかにかかっています.
i.書き換えまたは再定義した場合、SubとSubSubSubが同じパッケージにあるかどうかを確認します.
                      ii.なければ、BaseとSubSubSubが同じパッケージにあるかどうかを見ます.
3.他のクラスOtherでは、外部アクセス形式のみがサポートされていますが、OtherがBaseと同じパッケージを要求するか、OtherとSubと同じパッケージを要求するかは、あなたのアクセス方法によって異なります.
a.親参照「Basex=new XXX();x.YYY;」形式でアクセスする場合、OtherはBaseと同じパッケージを要求します.
b.サブクラス参照で「Subx=new Sub();x.YYY;」形式でアクセスすると、状況は複雑になります.この場合、サブクラスSubが親ベースのprotectedメソッドとプロパティを書き換えたかどうか、または再定義したかどうかを確認することが重要です.
i.書き換えまたは再定義した場合、OtherはSubと同じパッケージを要求すればよい.
                      ii.書き換えや再定義がされていない場合は、OtherにBaseと同じパッケージを要求すればよい.
 
 
また、ここまで书いて私はObjectの中のcloneの方法を思いついて、どうしてクローンの能力を持つクラスがCloneableインタフェースとcloneの方法を実现することを要求します:Object.clone()アクセス修飾子はprotectedである、あるクラスがこのメソッドを書き換えていない場合、Object中のclone()メソッドは、自分とサブクラスがメソッドを呼び出すことができるほか、このクラスと同じパッケージでも異なるパッケージでも見えない.書き換えていないか、Object中のメソッドであるか、javaにあるからである.langパッケージでは、定義したパッケージはjavaではありません.langパッケージでは、アクセスできません(これもプログラムでObject o=new Object()を定義しています).現在のクラスでo.clone()を呼び出すことはできません.同じように)、これもちょうど上の3に合っています.b.iiこのルール.したがって、異なるパッケージ内の非サブクラスにクローンできるようにするには、Objectを書き換える必要がある.clone()は、publicにアクセス権を設定します(書き換え後もprotectedの場合、同じパケットのみアクセスできます).
 
以上が私のprotected制限に対する理解であり、まだ漏れているところがあるに違いない.みんなに指摘してもらいたい.私はそれを改善します.もしあなたに役に立つなら、応援してください.
 
発見されたばかりの小さな問題には、「protected、これは間違っていますか?」を添付します.
 
どうもありがとうございました.皆さんの理解を見てみると、私の上の理解は確かに複雑です.これは継承訪問と非継承訪問を混同しているからこそ複雑です.実はこのように理解するのが最も簡単で、やはりその言葉で、protected修飾のメンバーはサブクラスとパッケージだけを許可します!ただし、サブクラスアクセス可能とは、継承アクセス、すなわち、サブクラスのインスタンスで親インスタンスを作成することによってアクセスするのではなく、継承されたprotectedメンバーに直接アクセスすることを意味します.パッケージアクセスとは、「XXX x=new XXX();x.YYY;」の方式でアクセスして、つまりインスタンスの引用を通じてアクセスして、アクセスできるかどうかはアクセスするコードのありかのクラスがクラスXXXと同じパッケージの中にあるかどうかを见ます.ただし、パッケージアクセスで注意したいのは、XXXで親のprotectedメンバーが継承されている場合、これらのメンバーを書き換えたり、再定義したりしない場合、アクセスできるかどうかは、現在アクセスしているコードが存在するクラスがクラスXXXの親と同じパッケージにあるかどうかにかかっています.また、クラスXXXがこれらのprotectedメンバーを書き換え、再定義した場合は、アクセスコードが存在するクラスとクラスXXXが同じパッケージにあるかどうかを直接見てください.
最後に注意したいのは、静的な保護されたメンバーが特殊であることです.protected staticメンバーは、布団クラスが書き換えられたり(厳密には書き換えとは呼ばない)、再定義されたりしても継承されます.つまり、サブクラスにはこのようなstatic protectedメンバーが2人います.ただし、彼らの所属ドメインだけです.(クラス)が異なるだけなので、子クラスが親と同じパッケージにあるかどうかにかかわらず、親のタイプで親に属するメンバーにアクセスできます.これは非静的とは異なります.
 
補足:方法は書き換えることができて、属性は書き換えることができますか