12

パブリックフィールドを実装する必要がある抽象クラスがあります。このフィールドはインターフェイスまたは別の抽象クラスです。

このようなもの:

public abstract class GenericContainer {
    public GenericChild child;
}

public abstract class GenericChild {
    public int prop1=1;
}

public abstract class SpecialChild extends GenericChild {
    public int prop1=2;
}

今、私は別の特殊なクラスコンテナを持っています:

public abstract class SpecialContainer extends GenericContainer {
    public SpecialChild child=new SpecialChild(); //PAY ATTENTION HERE!
}

Javaを使用すると、これをコンパイルできます。のフィールドが自動的にのフィールドをオーバーロードしているchildと想像してみてください...質問は次のとおりです。子の自動「オーバーロード」は発生しますか?SpecialContainerchildGenericContainer

そして、もっと重要な質問ですが、私がこのような別のクラスを持っている場合:

public class ExternalClass {
    public GenericContainer container=new SpecialContainer();
    public int test() {
         return container.child.prop1
    }
}

test()1または2を返しますか?私は、ジェネリックまたはスペシャルと呼ばGenericContainerれるコンテナフィールドを意味しますか?prop1そして、特別なprop1がStringとして宣言された場合はどうなりますか(はい、この場合もjavaでコンパイルできます)。

ありがとう!

4

6 に答える 6

15

Javaでは、データメンバー/属性はポリモーフィックではありません。オーバーロードとは、アクセスするクラスに応じてフィールドの値が異なることを意味します。サブクラスのフィールドはスーパークラスのフィールドを非表示にしますが、両方が存在します。フィールドは参照型に基づいて呼び出されますが、メソッドは実際のオブジェクトで使用されます。自分で試すことができます。

これは、変数の非表示/シャドウイングと呼ばれます。詳細については、こちらをご覧ください。

于 2013-03-09T14:29:23.553 に答える
12

これは何もオーバーライドしません。現在のクラススコープで元のフィールドを非表示にしているだけです。サブタイプを持つ変数を使用する場合でも、元のプロパティにアクセスできます。例:

abstract class GenericContainer {
    public GenericChild child;       
}

abstract class GenericChild {
    public int prop1=1 ;
}

class SpecialChild extends GenericChild {
    public int prop1=2;
}

class SpecialContainer extends GenericContainer {
    public SpecialChild child;
}

public class Main {

    public static void main( String ... args ) {

        GenericContainer container = new SpecialContainer();
        container.child = new SpecialChild();

        System.out.println( container.child.prop1 );

        SpecialChild child = (SpecialChild) container.child;        
        System.out.println( child.prop1 );
    }

}

これにより、1と2が出力されます。

からSpecialChildあなたはまた使用して1つのレベルに上がることができるでしょうsuper

class SpecialChild extends GenericChild {
    public int prop1=2;

    public int getOriginalProp1() {
        return super.prop1;
    }

}
于 2013-03-09T14:33:45.863 に答える
2

それにかんする

....そして、SpecialContainerのフィールド「child」がGenericContainerのフィールド「child」を自動的にオーバーロードしていると想像してください。

いいえ。フィールドはオーバーライドされません。オーバーライドされるのはメソッドのみです。

これが、フィールドへの直接アクセスよりも(オーバーライド可能な)getterメソッドとsetterメソッドの使用が好まれる理由の1つです。あなたのフィールドはほとんどすべてプライベートでなければなりません。

デザインに関しては、SpecialContainerクラスにSpecialChildフィールドを含める必要はありませんが、代わりにSpecialChildオブジェクトをGenericChildフィールドに配置する必要があります。

于 2013-03-09T14:27:21.030 に答える
2

なぜ誰もそのプログラムがスローするのを観察していないのですかNullPointerException
同じ名前のサブクラスfieldは、スーパークラスを非表示にしfieldます。ありませんoverridingfieldオーバーライドはメソッドでのみ可能です。

著者による元のコード:

public abstract class GenericContainer {
    public GenericChild child;
}

public abstract class GenericChild {
    public int prop1=1;
}

public abstract class SpecialChild extend GenericChild {
    public int prop1=2;
}

public abstract class SpecialContainer extends GenericContainer {
    public SpecialChild child=new SpecialChild(); //PAY ATTENTION HERE!
}

public class ExternalClass {
    public GenericContainer container=new SpecialContainer();
    public int test() {
         return container.child.prop1
    }
}
于 2013-03-09T15:25:48.067 に答える
1

Javaを使用すると、これをコンパイルできます。SpecialContainerのフィールド「child」がGenericContainerのフィールド「child」を自動的にオーバーロードしていると想像してみてください。

まず、継承は変数には適用されません。フィールド(Insatnce変数)はサブクラスでオーバーライドされません。フィールドは、いずれかでマークされている場合にのみサブクラスに表示されますpublic, protected or default

于 2013-03-09T14:27:54.813 に答える
1

あなたの質問に答えるために、それは両方のインスタンスを維持します。また、コンテナをどのように参照するか(抽象または実装のいずれかを介して)に応じて、参照する変数が決まります。

public class Test {

   public abstract class Container{
       public Generic gen = new Generic();
   }

   public class ContainerImpl extends Container{
       public GenericImpl gen = new GenericImpl();
   }

   public class Generic{
       public int prop = 0;
   }

   public class GenericImpl extends Generic{
       public int prop = 1;
   }

   public Test(){
       Container c = new ContainerImpl();
       System.out.println(c.gen.prop); // Outputs "0"
       System.out.println(((ContainerImpl)c).gen.prop); // Output "1"
   }

   public static void main(String[] args) {
      new Test();
   }

}

手元にあるより大きな問題は、なぜこのようなものを設計するのかということです。私はあなたが理論的な観点から質問していると仮定しています。

私の2セント、これは素晴らしいオブジェクト指向デザインではありません。パブリック変数をプライベートにし、コンストラクターまたはプロパティセッターを介してそれらの値を割り当てる方がよいでしょう。現状のままでは、コードに予期しない結果が生じる可能性があります。

于 2013-03-09T14:43:40.080 に答える