63

クラスは実行時に(ブロックからのように)メソッドをそれ自体に追加できますstatic。これにより、誰かがこのクラスでリフレクションを実行している場合、コンパイル時に定義されていなくても、新しいメソッドが表示されますか?

バックグラウンド:

私が使用しているフレームワークは、慣例により、メソッドActionを持つクラスが定義されることを期待しています。doAction(...)フレームワークは、実行時にこれらのクラスを検査して、doAction()メソッドで使用可能なパラメーターのタイプを確認します。例:doAction(String a、Integer b)

doAction()各クラスが、検査時にジャストインタイムで、さまざまなパラメーターを使用してプログラムでメソッドを生成できるようにしたいと思います。メソッドの本体は空にすることができます。

4

11 に答える 11

59

単純ではありません。クラスローダーによってクラスがロードされると、ロードされたクラスのメソッドを変更する方法はありません。クラスが要求されると、クラスローダーがそれをロードしてリンクします。また、リンクされたコードを変更したり、メソッドを追加/削除したりする方法は (Java では) ありません。

私の頭に浮かぶ唯一のトリックは、クラスローダーで遊ぶことです。カスタムクラスローダーを削除すると、そのクラスローダーによってロードされたクラスも削除されるか、アクセスできなくなります。私の頭に浮かぶ考えは、

  1. 1 つのカスタム クラスローダーを実装する
  2. そのカスタムクラスローダーで動的クラスをロードします
  3. このクラスの更新されたバージョンがある場合、
  4. カスタムクラスローダーを削除し、
  5. カスタム クラスローダーの新しいインスタンスを使用して、このクラスの新しいバージョンをロードする

これが解決策につながるのか、それとも落とし穴があるのか​​ を証明することはできません

質問に対する簡単な答えとして:いいえ、リフレクションでフィールドの内容を変更できるように、ロードされたクラスを変更することはできません。(フィールドを追加または削除することもできません)。

于 2011-07-13T14:53:32.233 に答える
24

Andres_D の言うとおりです。カスタム クラスの読み込みを使用して、これを行うことができます。これを行う方法の詳細なガイドは、http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic です。 html?ページ=1

この記事では、動的な Java コードを記述する方法について説明します。ランタイム ソース コードのコンパイル、クラスの再読み込み、および Proxy デザイン パターンを使用して、呼び出し元に対して透過的な動的クラスへの変更を行う方法について説明します。

実際、オーストリアの研究者は、異なる型階層を持つクラスをリロードすることさえできる JVM を作成しました。彼らは、既存のスレッドセーブポイントを使用して、オブジェクトの完全な「サイドユニバース」と、それに関連するすべての参照と参照コンテンツを生成し、必要なすべての変更で完全に再シャッフルすると、変更されたすべてのクラスを単にスワップすることでこれを達成しました。[1] ここに彼らのプロジェクトへのリンクhttp://ssw.jku.at/dcevm/オラクルのスポンサーシップは、将来の計画に関する興味深い推測を確かにします。


Java 1.4 ( docs.oracle.com/javase/1.4.2/docs/guide/jpda/enhancements ) で導入された JPDA の Hot Swap 機能を使用して、標準の Java VM でメソッドの本体とフィールドへの介入の少ない変更を行うことができます 。 html#ホットスワップ

それが最初のものかどうかは定かではありませんが、2001 年のこの Sun の従業員の論文は、HotSpot から Hot Swap への機能に言及した初期の提案の 1 つと思われます。[2]

参照

[1] T. Würthinger、C. Wimmer、および L. Stadler による「Dynamic Code Evolution for Java」は、2010 年にウィーンで開催された Java でのプログラミングの原則と実践に関する第 8 回国際会議で発表されました。

[2] M. Dmitriev、「Java 言語アプリケーションの実行時進化のための柔軟で安全なテクノロジーに向けて」、進化のための複雑なオブジェクト指向システムのエンジニアリングに関する OOPSLA ワークショップ、2001 年。

于 2012-09-14T23:26:57.537 に答える
10

私は自分でそのようなことを試したことはありませんが、ASMcglib、およびJavassistを確認する必要があります。

于 2011-07-13T14:41:44.670 に答える
5

いいえ、Java では (簡単に) 不可能です。

Java を動的プログラミング言語であるかのように使用しようとしているように思えます。たとえば、Ruby にはオープン クラスがあります。実行時に Ruby クラスのメソッドを追加および削除できます。Ruby では、クラスに存在しないメソッドを呼び出そうとすると呼び出される「メソッドが見つからない」メソッドをクラスに含めることもできます。そのようなこともJavaには存在しません。

JVM で実行される Ruby のバージョン JRuby があり、JVM でオープン クラスを機能させるには非常に難しいトリックを実行する必要があります。

于 2011-07-13T14:42:47.940 に答える
3

メソッドを動的に追加する方法がないようです。ただし、メソッドのリストまたは次のようなハッシュを使用してクラスを準備できます。

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;

public class GenericClass {
    private HashMap<String, Method> methodMap = new HashMap<String, Method>();

    public Object call(String methodName,Object ...args) 
               throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Method method = methodMap.get(methodName);
        return method.invoke(null, args);
    }

    public void add(String name,Method method){
        if(Modifier.isStatic(method.getModifiers()))
            methodMap.put(name, method);
    }

    public static void main(String[] args) {
        try   {
            GenericClass task = new GenericClass();
            task.add("Name",Object.class.getMethod("Name", new Class<?>[0]));
        } catch (NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }
   }
}

それよりも、反射を使用して属性を設定または設定解除できます。

于 2016-05-15T22:45:30.743 に答える
3

doAction生成されたメソッドに実行させたいことは何でも行うメソッドを持つことができます。生成する必要がある理由はありますか、それとも動的にすることができますか?

于 2011-07-13T14:42:56.797 に答える
2

プロキシが役立つ場合があります。ただし、メソッドを追加または削除するたびにプロキシをインスタンス化する必要があります。

于 2013-12-27T15:19:43.953 に答える
2

asm、cglib、javassist などのツール/フレームワークを変更するバイト コードが必要だと思います。Spring のようにアスペクト/ウィービングを介してこれを実現できますが、最初にメソッドを定義する必要があると思います。

于 2011-07-13T14:45:31.960 に答える
1

それが可能かどうかはわかりません。ただし、AspectJ、ASM などを使用して、これらのメソッドを適切なクラスに組み込むことができます。

もう 1 つの方法は、コンポジションを使用してターゲット クラスをラップし、doAction メソッドを提供することです。この場合、ターゲット クラスに委譲することになります。

于 2011-07-13T14:43:03.090 に答える