3

javassist を使用して、インターフェイスを実装するクラスを (実行時に) プログラムで作成およびコンパイルしようとしています。

その動的クラスのインスタンスを呼び出すたびに、次のエラーが発生します。

java.lang.AbstractMethodError: FooImpl.test()Ljava/lang/Object;

これが私のインターフェースです

public class FooBarInterface<T> {
    public T getEntity();
}

これがエンティティのサンプルです

public class FooEntity {

    @Override
    public String toString() {
        return "Hello, Foo!";
    }
}

インターフェイスをプログラムで実装する方法は次のとおりです

public void test() {
    ClassPool classPool = ClassPool.getDefault();
    CtClass testInterface = classPool.get(FooBarInterface.class.getName());

    CtClass fooImpl = classPool.makeClass("FooImpl");

    fooImpl.addInterface(testInterface);
    CtMethod testMethod = CtNewMethod.make(
        "public com.test.FooEntity getEntity(){" +
            "return new com.test.FooEntity();" +
        "}",
        canImpl
    );

    fooImpl.addMethod(testMethod);

    fooImpl.writeFile();

    TestInterface<FooEntity> test = 
        (TestInterface<FooEntity>) fooImpl.toClass().newInstance();

    System.out.println(test.getEntity());

}

実装されたメソッドの戻り値の型を Object に変更した場合、次のようにエラーは発生しません。

CtMethod testMethod = CtNewMethod.make(
    "public Object getEntity(){" +
        "return new com.test.FooEntity();" +
    "}",
    canImpl
);

その後、私は正常に取得しhello, Foo!ます。戻り値の型を Object に変更しても問題ありませんが、 Foo 型で返すと が生成される理由をもっと理解したいと思いますAbstractMethodError

4

3 に答える 3

2

JVM 内では、戻り値の型が異なるメソッドは区別されます。型消去後、型FooBarEntity.getEntity()を返しObjectます。インターフェイスを介した呼び出しは、戻り値の型を持つメソッドを特に探します。Objectしたがって、実装が返さなければならない理由はObject.

通常、Java コンパイラは具象メソッドの結果を消去された型として転送するブリッジ メソッドを作成しますが、明らかに Javassist はこれを行いません (私は Javassist を使用したことがないので、よくわかりません)。

ブリッジ メソッドを使用して型消去を実装する方法の詳細については、ブリッジ メソッドに関する Java チュートリアルの公式トピックを参照してください。

于 2014-05-12T05:27:59.173 に答える
1

私は同じエラーを抱えていました。新しい抽象メソッドを宣言した基本クラスがありました。私はそれを消費していた他のクラスにそのメソッドを実装しました。デバッグ中に、メソッドの実装に到達するとすぐに抽象メソッドエラーが発生しました。

解決策-: 基本クラスが他のアーティファクトによっても消費されていることがわかり、それらのアーティファクトで新しく作成された抽象メソッドをオーバーライドしませんでした。それらを変更していなかったのでビルドしたことがないため、JVM はコンパイル時エラーをスローすることはありませんが、実行時に例外が発生します。他のアーティファクトにメソッドを実装すると、例外を取り除くことができました。基本的に、私の場合、すべての子クラスには基本クラスの抽象メソッドが実装されていませんでした。

于 2015-04-10T19:07:30.610 に答える
0

パラメーター化されたパラメーターまたは戻り値の型がある場合、Java コンパイラーはそれを Object であるかのようにコンパイルし、もう一方を呼び出すパラメーター化されたシグネチャを使用してブリッジ メソッドを合成します。あるいはその逆かもしれません。合成したのは 1 つだけで、両方ではありません。

于 2014-05-12T05:28:59.920 に答える