Java:初心者っぽい継承の質問
-
03-07-2019 - |
質問
ベースクラスBと派生クラスDがあるとします。インスタンスがどのようなタイプの新しいオブジェクトも返す、ベースクラス内にメソッドfoo()が必要です。したがって、たとえば、B.foo()を呼び出すとタイプBのオブジェクトが返され、D.foo()を呼び出すとタイプDのオブジェクトが返されます。一方、実装は基本クラスBにのみ存在します。
これは可能ですか?
解決
しないでください。 " foo"を作りますメソッド抽象。
abstract class B {
public abstract B foo();
}
または、基本クラスコンストラクターを通じて抽象ファクトリを受け取ります:
abstract class B {
private final BFactory factory;
protected B(BFactory factory) {
this.factory = factory;
}
public B foo() {
return factory.create();
}
}
interface BFactory {
B create();
}
テイストに共変の戻り値の型とジェネリックを追加します。
他のヒント
各クラスにデフォルトのコンストラクタがある限り:
public B instance() throws Exception {
return getClass().newInstance();
}
まあ、オフにすることもできますが、「これ」以来常に現在のオブジェクトを参照します。次のようなことができます
public B foo() {
return this.getClass().newInstance();
}
またはそれらの線に沿って何か? Dのインスタンスを作成してからd.foo()を呼び出すと、Bとして返されるDのインスタンスを取得する必要があります。それをプレーンオブジェクトとして返すこともできますが、このインスタンスではできるだけ具体的にする必要があります。
これを達成したい場合、おそらく設計上の欠陥があると思うという事実とは別に、次のアプローチを試すことができます。
あなたの質問では、静的(クラス)メソッド、B.foo()、D.foo()を使用していますが、静的メソッドは動的な性質を持たないため、継承を使用してこれを達成することはできません。ルックアップシステムで。したがって、十分な型情報がありません。
メンバー関数foo()を使用している場合、次の構成を持つことができます。
public class B {
public B foo()
throws IllegalAccessException, InstantiationException {
return this.getClass().newInstance();
}
}
public class D extends B{
}
public class Test {
public static final void main(String[] args)
{
try {
System.out.println((new B()).foo());
System.out.println((new D()).foo());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
他の回答にあるように、各サブクラスに引数のないコンストラクターがある場合は、getClass()。newInstance()を使用できます(InstantiationExceptionおよびIllegalAccessExceptionをキャッチするようにしてください)。
いずれかのコンストラクターに引数が必要な場合、リフレクションを使用するか、必要に応じてサブクラスでオーバーライドできるgetNewInstance()のようなメソッドを定義することができます(私の見解では望ましい)。
e.g。
Thing foo() {
Thing th = getNewInstance();
// do some stuff with th
return th;
}
Thing getNewInstance() {
return getClass().newInstance();
}
getNewInstance()は、デフォルトのコンストラクターを持たないサブクラスに対して、本当に必要な場合にのみオーバーライドできます。
Thing getNewInstance() {
return new BigThing(10, ThingSize.METRES);
}
リフレクションを使用してこれを実行できる可能性があると思います、つまり、あなたが持っているスーパークラスで:
public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
return getClass().newInstance();
}
ClassNameは基本クラスの名前です。
使用したいところならどこでもキャストする必要があります...これが本当に素晴らしい解決策かどうかはわかりません!
編集:通常、newInstance()型のメソッドは静的です。もちろん、サブクラスの型が静的メソッドであるかどうかはわかりません。
static メソッドを取得して(動的に)サブクラスのインスタンスを作成する方法はないと思います。
@Rik
まあ、本当の問題は、抽象基底クラスThingがあることです。また、Thingには、Thingの新しいインスタンスを返すgetNextThing()というメソッドがあります。
次に、BigThing、LittleThing、SomethingThingなどのサブクラスがいくつかありますが、それぞれについてgetNextThing()メソッドを書き直したくありません。彼らはすべて同じことをするので、無駄に思えます...こと。
アプローチが間違っていますか?
なぜあなたが実際にやろうとしていることをやろうとしているのかわかりません。より多くのコンテキストを提供すると、より多くのヘルプを提供できる場合があります。
public class B <X extends B>{
public X foo() throws InstantiationException, IllegalAccessException{
return (X)this.getClass().newInstance();
}
}
public class C extends B<C>{
}
このアドバイスを提供させてください。 CSクラスが教えられる傾向は、教授が相続財産に夢中になっているが、構成を理解していないということです。あなたが探しているのは作曲だと思います。したがって、Thing自体でgetNextThingを呼び出す代わりに、Thingに繰り返し可能
これは、イテレータ。次のものを取得するロジックをカプセル化できます。継承モデルに収まらないようです。これのもう1つの利点は、これからいくつかの優れた構文デバイスを取得できることです(ループの理解が強化されます)。