6

抽象クラスがある場合は、具体的な匿名クラスを派生させることでインスタンス化できます。これは例です:

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)は正常に機能しますが、2番目のインスタンス化(y)は、具象クラスを派生させずに抽象クラスを直接インスタンス化しようとするため失敗します。ClassオブジェクトしかないJavaでこれを行うにはどうすればよいですか?

4

4 に答える 4

5

匿名クラスがどのように機能するかについて誤解しているかもしれません。匿名クラスは、実際には他のクラスと同じように通常のクラスであり、独自のクラスファイルを持っています。Java-the-languageは、これに対して構文上の糖衣構文を提供するだけであり、独自のファイルで通常の名前付き最上位クラスを宣言することで正確に模倣できるものに対して、より冗長でない構文を許可します。これが、ReflectionAPIが達成したいことには役に立たないことに気付く理由です。基本的に、クラスファイルを持たないクラスを動的に作成する必要があります。このためには、などの適切なライブラリが必要ですjavassist

于 2012-11-29T10:49:23.070 に答える
2

抽象クラスの代わりにインターフェースになる場合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();
    }
}
于 2012-11-29T10:34:44.940 に答える
0

抽象クラスはインスタンス化できないため、実際には、抽象クラスを拡張する新しい具象クラスが必要です。クラスは、Javaコンパイラによってソースコードから生成されます。したがって、そのソースコードを記述し、Javaコンパイラを実行します。Javaコンパイラはソースコードをファイルに常駐させる必要があり、コンパイルされたクラスもファイルシステムに配置するため、これを動的に行うのは簡単ではありませんが、可能です。Javaクラスを動的に生成する方法をご覧ください。次に、コンパイルされたクラスをロードする必要があります。これは別の話です。

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

于 2012-11-29T11:46:18.153 に答える
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」文字を出力する行がないので、それを期待する理由はないはずです。

于 2014-12-18T23:51:44.247 に答える