2009-12-23 12 views
6

Por favor, echar un vistazo a siguiente código:clases Anónimo interior dentro Métodos

import java.util.ArrayList; 
import java.util.List; 

class Main{ 
    public static <T> List<T> modifiedList(final List<T> list){ 
     return new ArrayList<T>(){ 
      @Override 
      public boolean add(T element){ 
       super.add(element); 
       return list.add(element); 
      } 
     }; 
    } 

    public static void main(String[] args) { 
     List<String> originalList=new ArrayList<String>(); 
     List<String> duplicateList=modifiedList(originalList); 
     originalList.add("1"); 
     originalList.add("2"); 
     originalList.add("3"); 
     System.out.println(originalList+" "+duplicateList); 
     duplicateList.add("4"); 
     duplicateList.add("5"); 
     duplicateList.add("6"); 
     System.out.println(originalList+" "+duplicateList); 
    } 

En el código anterior, la instancia de una clase interna anónima declarado en el método modifiedList() es capaz de acceder al parámetro que recibe ese método. AFAIK Java crea un archivo de código de bytes separado para las clases internas.

¿Alguien puede explicar cómo estos enlaces de variables locales son manejados por Java en el nivel de bytecode? Quiero decir, ¿cómo exactamente realiza Java un seguimiento de la referencia al objeto pasado como parámetro de ese método?

Cualquier ayuda sería muy apreciada!

[Lo siento por mi pobre inglés! Si entiende mi pregunta, modifique esta publicación y elimine los errores gramaticales. ! Gracias]

+0

Tu inglés es realmente bastante bueno. Solo hice algunos pequeños cambios gramaticales. :) – Amber

Respuesta

9

En esencia, el código se escribe de nuevo por el compilador como (nótese que no intenta compilar ..., podría tener errores):

class Main$1<T> 
    extends ArrayList<T> 
{ 
    private final List<T> list; 

    Main$1(final List<T> a) 
    { 
     list = a; 
    } 

    @Override 
    public boolean add(T element) 
    { 
     super.add(element); 
     return list.add(element); 
    } 
} 

y

class Main{ 
    public static <T> List<T> modifiedList(final List<T> list) 
    { 
     return new Main$1<T>(list); 
    } 

    public static void main(String[] args) 
    { 
     List<String> originalList=new ArrayList<String>(); 
     List<String> duplicateList=modifiedList(originalList); 
     originalList.add("1"); 
     originalList.add("2"); 
     originalList.add("3"); 
     System.out.println(originalList+" "+duplicateList); 
     duplicateList.add("4"); 
     duplicateList.add("5"); 
     duplicateList.add("6"); 
     System.out.println(originalList+" "+duplicateList); 
    } 
+0

Es por eso que el compilador necesita que se declare final. Para garantizar que el valor nunca cambie, el método dentro de la clase interna puede acceder al valor copiado sin cambios y saber que esa es la semántica correcta. Si no fuera final, no debería saber si el valor cambió entre la creación del objeto interno y la invocación del método del objeto interno. – helios

5
import java.util.ArrayList; 
import java.util.List; 

class Main{ 
    public static <T> List<T> modifiedList(final List<T> list){ 
     return new ArrayList<T>(){ 

      private List<T> originalList=list; 

      @Override 
      public boolean add(T element){ 
       super.add(element); 
       return originalList.add(element); 
      } 
     }; 
    } 

    public static void main(String[] args) { 
     List<String> originalList=new ArrayList<String>(); 
     List<String> duplicateList=modifiedList(originalList); 
     originalList.add("1"); 
     originalList.add("2"); 
     originalList.add("3"); 
     System.out.println(originalList+" "+duplicateList); 
     duplicateList.add("4"); 
     duplicateList.add("5"); 
     duplicateList.add("6"); 
     System.out.println(originalList+" "+duplicateList);  
    } 
} 

Java permite algo tan extraño solo para facilitar las cosas a los programadores. Ambos códigos son semánticamente iguales y se reducen al bytecode idéntico.

Cuestiones relacionadas