2012-04-06 30 views
7

Mam możliwość rozszerzenia klasy podczas kompilacji, ale muszę mieć możliwość utworzenia instancji tej podklasy w czasie wykonywania przy użyciu instancji nadklasy, która została już utworzona.Java: Rozszerzanie klasy w środowisku wykonawczym

Teoretycznie powinno być możliwe, ponieważ konstruktory superklasy są już wywoływane przed konstruktorem podklasy.

Nie mam wystarczającego dostępu do programu, aby zmienić instancję na moją podklasę i przerwać oryginalną instancję.

Przypadek użycia: Istnieje istniejąca tablica wystąpień klasy X. Mój kod jest ładowany po. Muszę nadpisać jedną z metod jednej z instancji X, gdy moja załadowana podklasa Y rozszerza X. Program nadrzędny uzyskuje dostęp do obiektów tylko przez tę tablicę, więc chcę zastąpić ten element tablicy moją instancją Y, ale musi zachowuj się tak, jakby był oryginalnie utworzony w tej macierzy. Nie mogę po prostu zamknąć instancji nadklasy i przekazywać połączeń, i istnieją trudne komplikacje z przywracaniem superklasy.

Mam nadzieję, że jest bardziej zrozumiały.

+3

Proszę ponownie sformułować pytanie. –

+1

Czy możesz również podać przykład tego, co faktycznie chcesz osiągnąć? Zamiast tylko pożądanej, ale możliwie niemożliwej, metody robienia tego. – millimoose

+0

Załóż istniejącą linię "public static Foo foo = new Foo();" że nie mogę się zmienić. Mam "public class Bar extend Foo" i chcę zrobić "foo = new Bar (...)" tak, jakby było tak, jakby pierwszy wiersz był "public static Foo foo = new Bar()". – JAKJ

Odpowiedz

5

Aby powtórzyć, co próbujesz zrobić ..

Wewnątrz JVM istnieje instancja klasy A. Chcesz dynamicznie modyfikować heiarchię klasy ClassA, tak aby istniała nowa klasa o nazwie ClassB, która pochodzi z ClassA. Następnie chciałbyś utworzyć instancję klasy B, ale jej implementacja podklasy powinna być instancją klasy ClassA. Coś jak wymiana pamięci.

Możesz zajrzeć do http://www.jboss.org/javassist. Trzeba będzie zastąpić ClassLoader, a następnie określić, kiedy ładowana jest klasa ClassA, a następnie utworzyć instancję. Będziesz wtedy musiał skonstruować ClassB i zwrócić go zamiast tego.

Aktualizacja

Po trochę więcej badań jest jeszcze możliwość, możesz robić, co chcesz. IDE działa podobnie do Eclipse, obsługując implementację metody HotSwap podczas debugowania. Korzystają z interfejsu Instrumentation API.

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

Można zastąpić ciała metody, ale nie dodawać lub usuwać Metody siebie. Więc dopóki nie będziesz w stanie zmienić typu na nowy typ, możesz całkowicie zastąpić implementację metody nową implementacją.

+0

Nie zmieniam dziedziczenia w czasie wykonywania, ale tylko tworzenie instancji podklasy, gdy jej nadklasa jest już utworzona. – JAKJ

+0

@JAKJ Odpowiedź jest wciąż taka sama. Masz istniejący obiekt, który chcesz dostosować do innego typu obiektu. JEŚLI możesz kontrolować początkowy punkt powrotu tego nowego obiektu, możesz go dostosować i zwrócić żądaną instancję. Sugeruję, abyś zaktualizował swoje pytanie za pomocą Przypadku użycia, a nie tego, co uważasz za rozwiązanie. –

+0

Nie mam możliwości zastąpienia programu ładującego klasy, ponieważ moja klasa jest ładowana po nadklasie i nie można używać środowisk wykonawczych innych firm. To musi być w języku Java. – JAKJ

1

Przeglądasz serwery Java Proxies?

Oto urywek z Javadoc:

„dynamiczne klasy proxy (w skrócie określane jako klasa proxy poniżej) to klasa, która implementuje listę interfejsów określonych w czasie wykonywania, gdy klasa jest tworzona”

+0

Wygląda na to, że serwery proxy są przeznaczone dla interfejsów, a nie dla klas. – JAKJ

3

Sugerowałbym użyciu cglib:

cglib jest potężnym, wysoka wydajność i jakość Code Generation biblioteka, jest ona wykorzystywana do rozszerzenia klas Javy i implementuje interfejsy przy starcie

You może znaleźć kilka przykładów tutaj: https://github.com/cglib/cglib/wiki

2

Nie wiem, czy to jest rozwiązanie, ale jeśli masz

public static Foo foo = new Foo(); 

i chcesz go zastąpić Bar, który rozciąga Foo zrobić Bar to jest nakładką na Foo i użyć refleksji niech punkt foo do instancji Bar.

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

i

// 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); 

}

Jak powiedział, nie wiem czy jest to możliwe w Twoim przypadku.

Powiązane problemy