基本クラス B と派生クラス D があるとします。基本クラス内に、インスタンスの型に関係なく新しいオブジェクトを返すメソッド foo() が必要です。たとえば、B.foo() を呼び出すと B 型のオブジェクトが返され、D.foo() を呼び出すと D 型のオブジェクトが返されます。一方、実装は基本クラス B にのみ存在します。
これは可能ですか?
基本クラス 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();
}
他の回答が言うように、各サブクラスに引数のないコンストラクターがある場合は、getClass()。newInstance()を使用できます(InstantiationExceptionとIllegalAccessExceptionを必ずキャッチしてください)。
コンストラクターのいずれかに引数が必要な場合は、リフレクションを使用するか、(私の見解では望ましい)getNewInstance()のようなメソッドを定義して、必要な場合にのみサブクラスでオーバーライドできます。
例えば
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);
}
これを実現したいのであれば、おそらく設計上の欠陥があると思うという事実とは別に、次のアプローチを試すことができます。
あなたの質問では、静的(クラス)メソッド、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();
}
}
}
これは、リフレクションを使用して実行できる可能性があると思います。つまり、スーパークラスでは次のようになります。
public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
return getClass().newInstance();
}
ClassName は基本クラスの名前です。
ただし、使用したい場所にキャストする必要があります...これが本当に優れたソリューションかどうかはわかりません!
編集: newInstance() タイプのメソッドは通常静的であり、もちろん、静的メソッドを使用したサブクラスのタイプが何であるかはわかりません。
サブクラスのインスタンスを(動的に)作成するための静的メソッドを取得する方法はないと思います。
まあ、私はオフにすることができますが、「これ」は常に現在のオブジェクトを参照するので、次のようなことができると思います
public B foo() {
return this.getClass().newInstance();
}
またはそれらの線に沿った何か?D のインスタンスを作成してから d.foo() を呼び出すと、D のインスタンスが B として返されます。プレーンなオブジェクトとして返すこともできますが、このインスタンスではできるだけ具体的にする必要があると思います。
なぜあなたが実際にやろうとしていることをやろうとしているのかわかりません。より多くのコンテキストを提供することで、より多くのヘルプを提供できる可能性があります。
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にIterableを実装させることを検討する必要があります。
これは、継承モデルに適合していないように見えるため、次のものを取得するロジックをカプセル化できるイテレータを作成する必要があることを意味します。これのもう1つの利点は、これからいくつかの優れた構文デバイスを取得できることです(ループ理解のために強化されています)。
@リック
さて、本当の問題は、私が抽象基本クラス Thing を持っていることです。Thing には、Thing の新しいインスタンスを返す getNextThing() というメソッドがあります。
次に、BigThing、LittleThing、SomethingThing などのサブクラスがいくつかありますが、それぞれの getNextThing() メソッドを書き直したくありません。彼らは皆同じことをしているので、それは無駄に思えます.
私のアプローチは間違っていますか?