【问题标题】:Anonymous Inner Classes Inside Methods方法内部的匿名内部类
【发布时间】:2009-12-23 05:10:20
【问题描述】:

请看下面的代码:

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

在上面的代码中,在方法 modifiedList() 中声明的匿名内部类的实例能够访问传递给该方法的参数。 AFAIK Java 为内部类创建一个单独的字节码文件。

谁能解释一下 Java 在字节码级别如何处理这些局部变量绑定?我的意思是,Java 究竟如何跟踪对作为参数传递给该方法的对象的引用?

任何帮助将不胜感激!

[对不起我的英语不好!如果您理解我的问题,请编辑此帖子并删除语法错误。谢谢!]

【问题讨论】:

  • 你的英语其实还不错。我只做了一些小的语法改变。 :)

标签: java anonymous-inner-class


【解决方案1】:

基本上代码被编译器重写为(注意我没有尝试编译它......,可能有错误):

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

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

【讨论】:

  • 这就是编译器需要将它声明为final的原因。为了确保值永远不会改变,因此内部类中的方法可以访问复制的永不改变的值并知道这是正确的语义。如果它不是最终的,它不应该知道值是否在内部对象创建和内部对象方法调用之间发生了变化。
【解决方案2】:
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 允许这种奇怪的事情只是为了让程序员更容易。 这两个代码在语义上是相同的,归结为相同的字节码。

【讨论】: