匿名 class 实例中的最终参数存储在哪里?

Where is final parameter stored in anonymous class instance?

我有以下从 int 数组创建列表视图的静态工厂方法:

public static List<Integer> newInstance(final int[] numbers) {
    return new AbstractList<Integer>() {

        @Override
        public Integer get(int index) {
            return numbers[index];
        }

        @Override
        public int size() {
            return numbers.length;
        }
    };
}


public static void main(String[] args) {
    int[] sequence = {10, 20, 30};
    List<Integer> list = ListFactory.newInstance(sequence);
    System.out.println("List is "+list);

}

在 "Effective Java" 中,Joshua Bloch 提到了这个

as an Adapter that allows an int array to be viewed as a list of Integer instances.

但是,我记得 Adapter 使用组合,匿名列表实现的实例应该使用 int[] 作为成员字段。

如果 int[] 输入参数不是匿名列表实现的成员字段,它究竟存储在哪里?

如果有人能提供一些见解或一些链接以查找更多信息,我将不胜感激。

你可以用javac -d . -XD-printflat ListFactory.java看看编译器是如何理解内部class的。实际上,您的示例中有两个 Java class。 ListFactory(注意 numbers 是如何传递给 ListFactory 的构造函数的):

public class ListFactory {

    public ListFactory() {
        super();
    }

    public static List newInstance(final int[] numbers) {
        return new ListFactory(numbers);
    }
}

AbstractList:

的匿名实现的表示
class ListFactory extends AbstractList {
    /*synthetic*/ final int[] val$numbers;

    ListFactory(/*synthetic*/ final int[] val$numbers) {
        this.val$numbers = val$numbers;
        super();
    }

    @Override()
    public Integer get(int index) {
        return Integer.valueOf(val$numbers[index]);
    }

    @Override()
    public int size() {
        return val$numbers.length;
    }

    @Override()
    /*synthetic*/ public Object get(/*synthetic*/ int index) {
        return this.get(index);
    }
}

标记为合成的方法和字段由编译器生成,您作为程序员无法访问,但在运行时用于访问 int 数组。确实有一个 val$numbers 字段包含对 int 数组的最终引用。

顺便说一下,您还可以注意到 Integer get(int index) 中从 intInteger 的装箱,并且符合原始(非通用)List 接口生成额外的 Object get(int index) 方法,委托给类型安全的 Integer get(int index) 实现。

它存储在 AbstractList 的匿名 class 中作为合成字段。您可以使用 javap 实用程序查看它:

final class q34290420.Test extends java.util.AbstractList<java.lang.Integer> {
  final int[] val$numbers;   // here
  q34290420.Test(int[]);
  public java.lang.Integer get(int);
  public int size();
  public java.lang.Object get(int);
}

另外你可以通过反射发现它:

    Field[] fields = list.getClass().getDeclaredFields();
    System.out.println(fields[0].getName());
    System.out.println(fields[0].isSynthetic());

输出:

val$numbers
true

这与问题有关:Why are only final variables accessible in anonymous class?

Jon Skeet 已经为上述问题提供了 succinct answer :

When you create an instance of an anonymous inner class, any variables which are used within that class have their values copied in via the autogenerated constructor. This avoids the compiler having to autogenerate various extra types to hold the logical state of the "local variables".

所以在这种情况下,int[] 数字会自动复制到从 AbstractList 扩展为合成字段的匿名 class。