web-dev-qa-db-ja.com

サブクラスが別のパッケージにある場合、サブクラスがスーパークラスの保護された変数にアクセスできないのはなぜですか?

database.relationパッケージにrelationという抽象クラスと、database.operationsパッケージにそのサブクラスJoinがあります。 relationには、mStructureという名前の保護されたメンバーがあります。

Join内:

public Join(final Relation relLeft, final Relation relRight) {
        super();
        mRelLeft = relLeft;
        mRelRight = relRight;
        mStructure = new LinkedList<Header>();
        this.copyStructure(mRelLeft.mStructure);

        for (final Header header :mRelRight.mStructure) {
        if (!mStructure.contains(header)) {
            mStructure.add(header);
        }
    }
}

オンラインで

this.copyStructure(mRelLeft.mStructure);

そして

for (final Header header : mRelRight.mStructure) {

次のエラーが発生します。

フィールドRelation.mStructureは表示されません

両方のクラスを同じパッケージに入れると、これは完全に機能します。誰でもこの問題を説明できますか?

31
Amir Rachum

動作しますが、子だけがアクセスしようとしますown変数であり、他のインスタンスの変数ではありません(同じ継承ツリーに属している場合でも)。

理解を深めるには、次のサンプルコードをご覧ください。

//in Parent.Java
package parentpackage;
public class Parent {
    protected String parentVariable = "whatever";// define protected variable
}

// in Children.Java
package childenpackage;
import parentpackage.Parent;

class Children extends Parent {
    Children(Parent withParent ){
        System.out.println( this.parentVariable );// works well.
        //System.out.print(withParent.parentVariable);// doesn't work
    } 
}

withParent.parentVariableを使用してコンパイルしようとすると、次のようになります。

Children.Java:8: parentVariable has protected access in parentpackage.Parent
    System.out.print(withParent.parentVariable);

アクセス可能ですが、独自の変数にのみアクセスできます。

25
OscarRyz

保護されている についてのほとんど知られていない警告:

6.6.2保護されたアクセスの詳細

オブジェクトの保護されたメンバーまたはコンストラクターは、そのオブジェクトの実装を担当するコードによってのみ宣言されているパッケージの外部からアクセスできます。

13
Marcus Adams

protectedの場合、Joinのインスタンスは、パッケージ外の他のインスタンス(mStructurerelRight)のrelLeftにアクセスできません。

編集:

here は、この状況をかなりよく説明しています。質問の犯人に[]sのマークを付けました

Access Levels
Modifier    Class Package Subclass  World
public      Y     Y       Y         Y
protected   Y    [Y]      Y         N
no modifier Y     Y       N         N
private     Y     N       N         N
2
Lauri Lehtinen

問題は、他のインスタンス保護メンバーにアクセスしていることです。

複数のソリューションを適用できます。たとえば、可能であれば、親クラスで次の2つのメソッドを宣言できます。

protected void copyRelationStructure(Relation r) {
  this.copyStructure(r.mStructure);
}

protected void mergeRelationStructure(Relation r) {
  for (final Header header: r.mStructure) {
    if (!mStructure.contains(header)) {
      mStructure.add(header);
    }
  }
}

そして、子コードで以下を置き換えます:

this.copyStructure(mRelLeft.mStructure);

for (final Header header :mRelRight.mStructure) {
  if (!mStructure.contains(header)) {
    mStructure.add(header);
  }
}

と:

this.copyRelationStructure(mRelLeft);
this.mergeRelationStructure(mRelRight);

うまくいくはずです。現在、Relationは、自身の内部での操作を子に許可するメソッドを提供する責任があります。おそらく、このポリシーの背後にある理由は、非互換性を制限するために、同じソフトウェアバンドルの一部でない限り、子供が親の内部を混乱させてはならないことです。

0
user1039663