2010-03-02 14 views
9

In Java, ogni volta che viene creata un'istanza di classe interna, questa viene associata a un'istanza di una classe esterna. Per curiosità, è possibile associare la classe interna ad un'altra istanza di una classe esterna?È possibile modificare l'istanza di classe esterna di una classe interna in Java?

+0

A parte il suo potenziale nei futuri contest offuscati di Java, qual è il punto? Sai che se vuoi una classe interiore che può essere dissociata dal suo genitore puoi semplicemente dichiararla statica, giusto? –

+0

Trovo affascinante questo problema. Qualcuno sa dove nel JLS è specificato come viene chiamato il puntatore alla classe esterna? Attraverso la sperimentazione, trovo che sia "questo $ 0", aggiunto da tanti "$" se necessario (forse nessuno). Questo è effettivamente specificato? – polygenelubricants

+0

OK Ho appena scoperto che una classe interna di secondo livello usa invece questo $ 1. Affascinante! – polygenelubricants

risposta

6

Sì, questo è possibile, anche se suona come una pessima idea per me. L'idea è di impostare il puntatore altrimenti final sull'istanza esterna usando reflection (che non è garantito per avere successo).

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 cruciale è outerThis.setAccessible(true); - un SecurityManager potrebbe applicare una politica che vieta questo da riuscire.

4

Si dovrebbe essere in grado di, utilizzando la riflessione.

Basta avere tutti i campi della classe interna (getClass().getDeclaredFields()) e vedere quale campo detiene il genitore, poi modificarlo (usando field.set(innerInstance, newParent) Prima che si dovrebbe rendere il campo accessibili -. setAccessible(true))

Poiché il campo sembra essere final, si può dare un'occhiata a this article per vedere come aggirarlo.

Detto questo, non avresti bisogno di farlo affatto - sarebbe un brutto doppio brutto per nessun guadagno reale.

5

Se si sta parlando sul tempo di istanze, è possibile utilizzare la seguente sintassi:

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

Tuttavia, non è possibile (senza setAccessible(true)) per associare l'istanza esistente di classe interna con l'altra istanza di classe esterna , perché il campo che indica l'istanza allegando è 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) buon posto con il 'finale'. – Bozho

+0

+1 per 'o.new Inner()' - Ho imparato una nuova sintassi oggi. –

Problemi correlati