匿名 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)
中从 int
到 Integer
的装箱,并且符合原始(非通用)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。
我有以下从 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)
中从 int
到 Integer
的装箱,并且符合原始(非通用)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。