パブリックフィールドを実装する必要がある抽象クラスがあります。このフィールドはインターフェイスまたは別の抽象クラスです。
このようなもの:
_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この場合もコンパイルできます))?
ありがとう!
これは何もオーバーライドするのではなく、現在のクラススコープで元のフィールドを非表示にするだけです。サブタイプを持つ変数を使用する場合でも、元のプロパティにアクセスできます。例:
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;
}
}
Javaでは、データメンバー/属性はポリモーフィックではありません。オーバーロードとは、アクセスするクラスに応じてフィールドの値が異なることを意味します。サブクラスのフィールドはスーパークラスのフィールドを非表示にしますが、両方が存在します。 フィールドは参照型に基づいて呼び出されますが、メソッドは実際のオブジェクトで使用されます。自分で試すことができます。
これは、変数の非表示/シャドウイングと呼ばれます。詳細については、 ここ を参照してください。
について
....そして、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デザイン。パブリック変数をプライベートにし、コンストラクターまたはプロパティセッターを介してそれらの値を割り当てる方がよいでしょう。現状のままでは、コードに予期しない結果が生じます。
Javaを使用すると、これをコンパイルできます。SpecialContainerのフィールド「child」がGenericContainerのフィールド「child」を自動的にオーバーロードしていると想像してみてください。
まず、継承は変数には適用されません。フィールド(Insatnce変数)はサブクラスでオーバーライドされません。public, protected or default
のいずれかでマークされている場合にのみ、サブクラスで表示されます。
プログラムが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
}
}