web-dev-qa-db-ja.com

Java抽象クラスフィールドのオーバーライド

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

このようなもの:

_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!
}
_

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

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

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

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

ありがとう!

11
Alex

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

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から、superを使用して1レベル上に移動することもできます。

class SpecialChild extends GenericChild {
    public int prop1=2;

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

}
11

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

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

14

について

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

いいえ。フィールドは上書きされません。上書きされるのはメソッドだけです。

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

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

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

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セント、これは素晴らしいことではありませんOOデザイン。パブリック変数をプライベートにし、コンストラクターまたはプロパティセッターを介してそれらの値を割り当てる方がよいでしょう。現状のままでは、コードに予期しない結果が生じます。

1
J. Rambo

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

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

1
PermGenError

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

著者による元のコード:

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
    }
}
1
AmitG