2012-04-06 23 views
7

Tengo la capacidad de extender una clase en tiempo de compilación, pero necesito poder crear una instancia de esta subclase en tiempo de ejecución usando una instancia de la superclase que ya se creó una instancia.Java: Extendiendo clase en tiempo de ejecución

Esto debería ser posible en teoría porque los constructores de superclase ya están llamados antes del constructor de la subclase.

No tengo acceso al programa lo suficiente como para cambiar la instanciación a mi subclase ni para interrumpir la instanciación original.

Caso de uso: existe una matriz existente de instancias de clase X. Mi código se carga después. Necesito anular uno de los métodos de una de las instancias X con mi subclase cargada Y extiende X. El programa padre accede a los objetos solo a través de esa matriz, por lo que quiero reemplazar ese elemento de la matriz con mi instancia Y, pero necesita comportarse como si hubiera sido instanciado originalmente en esa matriz. No puedo simplemente encerrar la instancia de superclase y reenviar llamadas, y hay complicaciones difíciles con la reinstalación de la superclase.

Espero que sea más claro.

+3

Por favor, vuelva a formular la pregunta. –

+1

¿Puedes dar también un ejemplo de lo que realmente estás tratando de lograr? En lugar de simplemente su método deseado, pero posiblemente imposible, para hacerlo. – millimoose

+0

Supongamos que la línea existente "public static Foo foo = new Foo();" que no puedo alterar Tengo "clase pública Bar extiende Foo" y quiero hacer "foo = new Bar (...)" tal que era como si la primera línea fuera "public static Foo foo = new Bar()". – JAKJ

Respuesta

5

Para reiterar lo que está intentando hacer ...

Dentro de la JVM, existe una instancia de ClassA. Le gustaría modificar dinámicamente el heiarchy de clase de ClassA, de modo que exista una nueva clase llamada ClassB que se deriva de ClassA. Luego, le gustaría crear una instancia de ClassB pero su implementación de subclase debe ser la de la instancia existente de ClassA. Algo así como un reemplazo de memoria.

Es posible que desee consultar http://www.jboss.org/javassist. Lo que tendría que hacer es reemplazar el ClassLoader, luego determinar cuándo se está cargando ClassA, y luego crear una instancia. Entonces necesitaría construir ClassB y devolverlo en su lugar.

actualización

Después de investigar un poco más todavía existe la posibilidad, se puede hacer lo que quiera. IDE es como Eclipse compatible con las implementaciones del método HotSwap'ing durante la depuración. Usan la API de Instrumentación.

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

Puede reemplazar cuerpos de los métodos, pero no agregar o quitar métodos de sí mismos. Entonces, si bien no podrá cambiar el tipo a su nuevo tipo, puede reemplazar completamente la implementación del método con su nueva implementación.

+0

No estoy cambiando la herencia en tiempo de ejecución, pero solo instanciando una subclase cuando su superclase ya está instanciada. – JAKJ

+0

@JAKJ La respuesta sigue siendo la misma. Tiene un objeto existente que desea Adaptar a otro tipo de objeto. SI puede controlar el punto de retorno inicial de este nuevo objeto, entonces puede Adaptarlo y devolver la instancia que desee. Le sugiero que actualice su pregunta con su Caso de uso, no es lo que cree que es la solución. –

+0

No tengo la capacidad de reemplazar el cargador de clases ya que mi clase se carga después de la superclase ni puedo usar tiempos de ejecución de terceros. Esto debe estar dentro de Java. – JAKJ

1

¿Has mirado los Proxies de Java?

Aquí hay un fragmento de Javadoc:

"Una clase proxy dinámico (denominado simplemente como una clase de proxy a continuación) es una clase que implementa una lista de interfaces especificadas en tiempo de ejecución cuando se crea la clase"

+0

Parece que los proxies son para interfaces, no para clases. – JAKJ

3

se recomienda usar cglib:

cglib es un poderoso, de alto rendimiento y la calidad de generación de código Biblioteca, Se utiliza para extender las clases JAVA e implementa las interfaces en tiempo de ejecución

Usted Puede encontrar algunos ejemplos aquí: https://github.com/cglib/cglib/wiki

2

No sé si es una solución pero si tiene

public static Foo foo = new Foo(); 

y desea reemplazarlo con barra que se extiende Foo hacer una envoltura de barra de Foo y el uso de reflexión para que el punto foo a la instancia bar.

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

y

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

}

Como se le dijo que no sé si esto es posible en su caso.

Cuestiones relacionadas