2012-04-06 8 views
7

コンパイル時にクラスを拡張する機能がありますが、すでにインスタンス化されたスーパークラスのインスタンスを使用して実行時にこのサブクラスのインスタンスを作成できる必要があります。Java:ランタイムでクラスを拡張する

これは、スーパークラスのコンストラクタがサブクラスのコンストラクタの前にすでに呼び出されているため、これは理論上可能です。

インスタンス化をサブクラスに変更したり、元のインスタンス化を中断したりするのに十分なほどプログラムにアクセスできません。

使用例:クラスXのインスタンスの既存の配列があります。後でコードが読み込まれます。インスタンスXのうちの1つのメソッドを、ロードされたサブクラスYがXを拡張するようにオーバーライドする必要があります。親プログラムはその配列を介してのみオブジェクトにアクセスするため、その配列要素をYインスタンスに置き換えます。あたかも元々その配列にインスタンス化されているかのように振る舞います。私は、スーパークラスのインスタンスとフォワードコールを囲むだけではいけません。スーパークラスを再インスタンス化するのは困難な複雑さがあります。

もっと明確になることを願っています。

+3

質問に言い換えてください。 –

+1

あなたは実際に達成しようとしているものの例を提供することはできますか?代わりにあなたの望む、しかし不可能な、そうする方法。 – millimoose

+0

既存の行を「public static Foo foo = new Foo();」とします。私は変更することはできません。私は "public class Bar extends Foo"を持っていて、最初の行が "public static Foo foo = new Bar()"のように "foo = new Bar(...)"を実行したいと思います。 – JAKJ

答えて

5

あなたがしようとしていることを繰り返してください..

JVM内にClassAのインスタンスが存在します。 ClassAから派生したClassBという新しいクラスが存在するように、ClassAのクラス階層を動的に変更したいとします。次に、ClassBのインスタンスをインスタンス化するが、サブクラスの実装はClassAの既存のインスタンスのインスタンスにすることができます。メモリ交換のようなもの。

http://www.jboss.org/javassistを参照してください。あなたがしなければならないことは、ClassLoaderを置き換え、ClassAがロードされているかどうかを判断し、次にインスタンス化することです。 ClassBを構築して代わりにそれを返す必要があります。

更新

はもう少し研究した後、まだあなたがやりたいことができます可能性があります。 EclipseのようなIDEは、デバッグ中にメソッドの実装をHotSwapingします。彼らはInstrumentation APIを使用します。

http://zeroturnaround.com/blog/reloading_java_classes_401_hotswap_jrebel/

あなたは自分自身を追加したり、メソッドを削除するメソッド本体を交換することはできませんが。したがって、タイプを新しいタイプに変更することはできませんが、メソッド実装を新しい実装に完全に置き換えることができます。

+0

実行時に継承を変更するのではなく、そのスーパークラスがすでにインスタンス化されている場合にのみサブクラスをインスタンス化します。 – JAKJ

+0

@JAKJ答えは同じです。別のタイプのオブジェクトに適応させたい既存のオブジェクトがあります。この新しいオブジェクトの最初のリターンポイントを制御できる場合は、それを適応させて、必要なインスタンスを返すことができます。私はあなたのユースケースを使ってあなたの質問を更新することをお勧めします。 –

+0

スーパークラスの後にクラスがロードされたり、サードパーティのランタイムを使用することができないため、クラスローダーを置き換えることができません。これはJava内でなければなりません。 – JAKJ

1

Javaプロキシを見ましたか?

「クラスが作成されるときに動的プロキシクラス(以下、単にプロキシクラスと呼ぶ)実行時に指定されたインタフェースのリストを実装するクラスである」:ここ

は、Javadocのからの抜粋であります

+0

プロキシはインターフェイスではなく、クラスであるようです。 – JAKJ

3

私はcglibを使用することをお勧めします:

CGLIBは、強力な、高い性能と品質のコード生成 図書館で、Javaクラスを拡張するために使用し、あなたはランタイム

でインターフェース を実装していますここにいくつかの例があります:

2

解決策であるかどうかわかりませんが、

public static Foo foo = new Foo(); 

は、あなたはFooの があなたのバーインスタンスへのfooポイントをできるようにfooと利用反射のためにバーにラッパーを作る拡張バーとそれを交換したいです。

public class Foo extends Bar { 
    private bar; 
    public Foo(Bar oldInstance) { 
    this.bar = oldInstance; 
    } 
} 

// exception handling ommitted 
public static void onStartup() { 
    Class fooRefClass = FooRef.class; 
    Field fooRef = fooRefClass.getDeclaredField("foo"); 

    Foo foo = (Foo)fooRef.get(null); 
    Bar bar = new Bar(foo); 
    fooRef.set(null, bar); 

}

Asこれはあなたのケースで可能であるか私にはわからないと語りました。

関連する問題