2011-01-13 13 views
6

私はJavaのReflectionで遊んでいます。私はコンストラクタを持つ抽象クラスBaseを持っています。リフレクトで抽象基底クラスからコンストラクタにアクセスする

abstract class Base { 
    public Base(String foo) { 
     // do some magic 
    } 
} 

さらに、いくつかのクラスがBaseに拡張されています。彼らは多くの論理を含んでいない。私はBaseのコンストラクタでそれらをインスタンス化したい、その派生クラスにプロキシコンストラクタを書く必要はありません。そして、もちろん、私はそれらの派生クラスをReflectionでインスタンス化したいと思います。と言う:

Class cls = SomeDerivedClass.class; 
Constructor constr; 
constr = cls.getConstructor(new Class[] { String.class }); // will return null 
Class clsBase = Base.class; 
constr = clsBase.getConstructor(new Class[] { String.class }); // ok 
Base obj = (Base) constr.newInstance(new Object[] { "foo" }); // will throw InstantiationException because it belongs to an abstract class 

私はBaseのコンストラクタでどのように派生クラスをインスタンス化できますか?またはとする必要があります。これらのダムプロキシコンストラクタを宣言しますか?

+0

これらのクラスをインスタンス化する前に、すべてがコンパイルされていることを確認してください。 – gabuzo

+0

はい、うまくコンパイルされます。これは簡単な例ですが、catch節が欠けていますが、基本的にこのコードはうまくコンパイルされます。ああ、 'Base'には空のデフォルトのコンストラクタが追加されています(javacはこれを主張しています)。 – craesh

答えて

9

クラスは親からのコンストラクタを継承しません。クラスには親コンストラクタはありません(ただし、それを呼び出すことはできます)。したがって、スーパークラスにはコンストラクタではなく、クラスにあるコンストラクタを呼び出さなければなりません。

既定のコンストラクタは、既定で親の既定のコンストラクタを呼び出すため、これを行うようにのみ見えます。親がデフォルトのコンストラクタを持たない場合、どちらも直接の子ではありません。

+0

私はあなたの答えを受け入れました。それは最も正確なものです。 – craesh

1

問題は、基本クラスのコンストラクタがデフォルトではない(パラメータを持つ)ことです。したがって、生成されたデフォルトのサブクラスコンストラクタによって暗黙的に呼び出すことはできません。 (実際にはこれに関するコンパイル警告/エラーが出るはずです)明示的なサブクラスのコンストラクタを追加する必要があると思います。

+0

私は警告を受けていませんでした。多分、 'Base'と派生したクラスが、異なるEclipseプロジェクトにある別々のパッケージにあるからです。 – craesh

2

super()コンストラクタの1つを呼び出す明示的なコンストラクタがあるまで、あなたのサブクラスはコンパイルされません。

+0

すべてがうまくコンパイルされます。 'Base(String)'はどのサブクラスでも呼び出されません。しかし、私は 'Base'の空のデフォルトコンストラクタを一度定義しなければなりませんでした。 – craesh

+0

しかしそれは重要な違いです。これは、あなたの子クラスがインスタンスをコンパイルすることを意味しますが、空の親コンストラクタを呼び出すだけです。子クラスがコンストラクタで明示的にそれを呼び出さない限り、他のコンストラクタにアクセスする方法はありません。 – biziclop

2

抽象クラスを作成する際に、抽象クラスを「抽象化しない」ようにするための詳細を指定することはできません。親のみのクラスが返される反射を介して操作コンストラクタのない量を

public abstract class Parent { 
    String name; 

    public Parent(String name) { 
    this.name = name; 
    } 

    abstract public String getName(); 

} 

:例では意味し

。ただし、そのように、施工時に抽象的な内容を指定することで、「匿名」クラスを返すことができます。

Parent parent = new Parent() { 
    public String getName() { return "Bob"; } 
    }; 

あなたは内のコードを入れていない場合でも、サブクラス化はまた、親のコンストラクタを呼び出して、覚えておいてください明示的に。以下のように書かれたサブクラス:

public class Child extends Parent { 
    public Child(String name) { 
    } 
} 

Parentクラスの引数なしのコンストラクタを探します。あなたが明示的に持つ親クラスの建設を指定するまで、それが1つを見つけた場合、それはParentクラスの引数なしのコンストラクタが見つからない場合、それは

public class Child extends Parent { 
    public Child(String name) { 
    super(); 
    } 
} 

にコードと同等にコンパイルされ、それがコンパイルに失敗しますsuper(name);コンストラクタ呼び出し

あなたがそうのようなextends SomeClassを提供していないので、もし、すべてのクラスがObjectのサブクラスである、覚えておくべきもう一つは:

public class JustMe { 
} 

コンパイラはconceputallyあなたがコンパイル時にコード「修正」:

public class JustMe extends Object { 

    public JustMe() { 
    super(); 
    } 
} 

Objectクラスには、JVMに登録するためのネイティブ(Java以外の)コードが含まれているため、Objectのライフサイクルにわたって正しいガベージコレクション、メモリ管理、タイプ強制などが確実に行われます。

ie。それを回避することはできません。JVMは、匿名のクラスやサブクラスを使用してメソッドをすべて解決できない限り、構築および抽象クラスを停止します。

+0

サブクラス化は、パラメーターなしの親コンストラクターが存在する場合は暗黙的に呼び出すことはありません。間違いなく、それ自体でパラメータを渡すことはありません。さらに、抽象クラスのコンストラクタにパラメータが必要な場合は、匿名クラスを作成するときにパラメータを指定する必要があります。例を挙げると、次のようになります。new Parent( "foo"){...} – biziclop

+0

@biziclop優れた観察、後世のために修正された投稿 –

+0

まだまだベスト・アンサー。 – milosmns