2010-03-02 26 views
9

En Java, cada vez que se crea una instancia de clase interna, se asocia con una instancia de una clase externa. Por curiosidad, ¿es posible asociar la clase interna con otra instancia de una clase exterior en su lugar?¿Es posible cambiar la instancia de clase externa de una clase interna en Java?

+0

Aparte de su potencial en futuros concursos de java ofuscados, ¿cuál es el punto? Sabes que si quieres una clase interna que pueda desasociarse de su padre, puedes declararla estática, ¿verdad? –

+0

Encuentro este problema fascinante. ¿Alguien sabe dónde en el JLS se especifica cómo se nombra el puntero a la clase externa? A través de la experimentación, me parece que parece ser 'este $ 0', a la que se añaden tantos '$' como sea necesario (posiblemente ninguno). ¿Esto está realmente especificado? – polygenelubricants

+0

OK Acabo de descubrir que una clase interna de segundo nivel usa 'this $ 1' en su lugar. ¡Fascinante! – polygenelubricants

Respuesta

6

Sí, esto es posible, a pesar de que suena como una muy mala idea. La idea es establecer el puntero de lo contrario final a la instancia externa utilizando reflexión (que no se garantiza que tenga éxito).

import java.lang.reflect.*; 

public class Me { 
    final String name; 

    Me(String name) { 
     this.name = name; 
    } 

    class InnerMe {  
     String whoAreYou() { 
      return name; 
     } 
    } 

    InnerMe innerSelf() { 
     return new InnerMe(); 
    } 

    public static void main(String args[]) throws Exception { 
     final Me me = new Me("Just the old me!"); 
     final InnerMe innerMe = me.innerSelf(); 
     System.out.println(innerMe.whoAreYou()); // "Just the old me!" 
     Field outerThis = innerMe.getClass().getDeclaredFields()[0]; 
     outerThis.setAccessible(true); 
     outerThis.set(innerMe, new Me("New and improved me!")); 
     System.out.println(innerMe.whoAreYou()); // "New and improved me!" 
    } 

} 

La parte crucial aquí es outerThis.setAccessible(true); - un SecurityManager podría imponer una política que prohíbe este tenga éxito.

4

Debería poder hacerlo, mediante el reflejo.

Acaba de obtener todos los campos de la clase interna (getClass().getDeclaredFields()) y ver qué campo tiene el padre, y luego cambiarlo (usando field.set(innerInstance, newParent) Antes de que usted debe hacer que el campo accesible -. setAccessible(true))

Puesto que el campo parece ser final, puede echar un vistazo a this article para ver cómo eludir eso.

Dicho esto, no debería necesitar hacer esto en absoluto; sería un truco feo doble sin ganancia real.

5

Si usted está hablando sobre el tiempo de instancias, es posible utilizar la siguiente sintaxis:

public class Outer { 
    public class Inner {} 
} 
... 
Outer o = new Outer(); 
Outer.Inner i = o.new Inner(); 

Sin embargo, no es posible (sin setAccessible(true)) para asociar la instancia existente de clase interna con la otra instancia de la clase externa , porque el campo que apunta a la instancia que encierra es final:

javap Outer$Inner 

Compiled from "Outer.java" 
public class Outer$Inner extends java.lang.Object{ 
    final Outer this$0; 
    public Outer$Inner(Outer); 
} 
+0

(+1) buen lugar con el 'final'. – Bozho

+0

+1 for 'o.new Inner()' - Hoy aprendí una nueva sintaxis. –

Cuestiones relacionadas