2012-11-29 7 views
6

抽象クラスがある場合は、具体的な匿名クラスを派生させて抽象クラスをインスタンス化できます。これは例です:JavaのClassオブジェクトに格納されている抽象クラスを匿名でインスタンス化する方法はありますか?

abstract class A { 
    abstract void hello(); 
} 

A say = new A() { void hello() { System.out.println ("hello"); } } 

say.hello(); // -> hello 

クラスがClassオブジェクトに格納されている場合、同じ操作を行うにはどうすればよいですか?ここでの例である:

// -*- compile-command: "javac anon.java && java anon"; -*- 

class anon 
{ 
    anon() throws Exception {} 

    abstract class AbstractClass 
    { 
     AbstractClass() throws Exception {} 
     abstract void id(); 
    } 

    AbstractClass x = new AbstractClass() 
     { 
      void id() { System.out.println ("X"); } 
     }; 

    Class<AbstractClass> abstractclass 
     = (Class<AbstractClass>)Class.forName ("anon$AbstractClass"); 

    AbstractClass y = abstractclass.getConstructor().newInstance(); 

    public static void main (String argv[]) throws Exception 
    { 
     anon main = new anon(); 
     main.x.id(); // should print "X" 
     main.y.id(); // should print "Y" 
    } 
} 

最初のインスタンス(x)が正常に動作しますが、それは、具体的なクラスを派生することなく直接抽象クラスをインスタンス化しようとするため、第二(y)は失敗します。 Classオブジェクトのみを持つJavaでこれを行うにはどうすればよいですか?

+0

待機。最初のコードで2番目の方法を実装しようとしましたか?私はそれがあまりにも機能しないと思う。なぜあなたはそのような抽象クラスをインスタンス化しようとしていますか?匿名クラスを作成すると、抽象クラス自体を拡張するのではなく、抽象クラスを実際に拡張してインスタンス化します。 –

+0

y.id()は "Y"を出力しません。 – ceving

+0

@ceving ..あなたのコメントが分かりましたか? –

答えて

5

匿名クラスがどの程度正確に機能するかについての誤解があるかもしれません。匿名クラスは実際に他のクラスと同様に通常のクラスであり、独自のクラスファイルを持ちます。 Java-the-languageはこれに対する文法的な砂糖を提供するだけで、それ自身のファイルで通常の名前のトップレベルクラスを宣言することで、まるで模倣できるような冗長な構文を可能にします。これは、あなたが達成したいものに対してReflection APIが役に立たないことがわかる理由です。基本的に、そのクラスファイルを持たないクラスを動的に作成したいとします。このためには、javassistのような適切なライブラリが必要です。

+0

あまりにも悪いです。 Javaを書く必要があるときはいつでも、Javaの制限を回避するのに十分な時間を費やさなければなりません。しかし、今回は壁が岩のように見えます。 – ceving

+1

まあまあです。 Javaをロックと比較することは、実際には非常に肥沃なアナロジーであり、多くの異なるケースで機能します。私は、Javaのレゴブロックとは対照的に、ルビーやJavaScriptのような動的言語のための粘土を想像したい。特定の狭く事前定義された方法でのみ連動します。 –

+0

私は何かを得るためにいくつかのレゴのレンガをスラブして自分自身を覚えていることができます。私はこの問題があることを遺伝子的に決定しなければならない。 – ceving

1

Aが抽象クラスではなくインターフェイスである場合は、これを動的プロキシで行うことはできますが、抽象クラスでは機能しません。

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 

interface A { 
    void hello(); 
} 

public class Example { 
    public static void main(String[] args) throws Exception { 
     @SuppressWarnings("unchecked") 
     Class<A> cls = (Class<A>) Class.forName("A"); 

     InvocationHandler handler = new InvocationHandler() { 
      @Override 
      public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable { 
       System.out.println(method.getName()); 
       return null; 
      } 
     }; 

     A instance = (A) Proxy.newProxyInstance(cls.getClassLoader(), 
      new Class<?>[] { cls }, handler); 

     instance.hello(); 
    } 
} 
+0

Hmmmは、私がまだ認識していない面白い新しいJavaの制限のように聞こえます。インタフェースではできますが、抽象クラスではできませんが、ほぼ同じです。 – ceving

0

抽象クラスをインスタンス化することはできないため、抽象クラスを拡張する新しい具象クラスが実際に必要です。クラスは、Javaコンパイラによってソースコードから生成されます。そのソースコードを書いてjavaコンパイラを実行してください。 Javaコンパイラはソースコードをファイルに格納する必要があり、コンパイルされたクラスもファイルシステムに格納する必要がありますが、動的に行うのは簡単ではありません。 Generating Java classes dynamicallyでどのように行われるべきかを見てください。次に、コンパイルされたクラスをロードする必要があります。これは別の話です。

これを「Javaの制限」と見なすと、あなたのタスクに間違った言語を選択した(または間違ったタスクを選択した)可能性があります。 JVMに基づいた動的言語を試してみてください:Groovy、JRuby ...そこにはたくさんのものがあります。

+0

言語を自由に選択できますか?あなたは幸運です! – ceving

+0

どこからでもjavaを使用できますが、このタスクではjavaからgroovyを呼び出します。 –

0

Markoが述べたように、匿名のクラスはファイルとバイトコードのレベルで他のクラスと同じです。小さなクラスを書くのを簡単にする言語レベルの構文的な砂糖です。

例では、x.getClass()abstractクラスではありません。これはAbstractClassのサブクラスであり、id()の定義ではもはやabstractではありません。それはおそらくanon$1のような名前を持っています。

もちろん抽象的であればインスタンス化できません。これはまさにあなたがyの割り当てでやろうとしていることです。あなたの反映はy = anon.AbstractClass();と等価で、id()を上書きします。コンパイル時にエラーが発生するように、リフレクションは実行時にエラーが発生します。

以下(他の匿名クラス、およびその順序の存在を依存する)可能性が高いだろうと、エラーなしで実行されますが、印刷「X」:

Class<AbstractClass> abstractclass 
    = (Class<AbstractClass>)Class.forName("anon$1"); // Note the different class name 
AbstractClass y = abstractclass.getConstructor().newInstance(); 
y.id(); // prints "X", not "Y" 

点まで...

main.y.id(); // should print "Y" 

あなたのコードのどこにも "Y"文字が印刷されていないので、それを期待する理由はありません。

+0

ライン印刷 "Y"の書き方はまさに問題でした。 – ceving

+0

あなたのコードで 'System.out.println(" Y ");が存在しません。あなたのコメント(コード内)は無効です。 – Anm

関連する問題