这是从JPL复制的(见下面的评论),我添加了import和main():
import java.util.*;
/**
* @From "The Java Programming Language" by Arnold, Gosling, Holmes
* (5.3. Local Inner Classes)
*/
public class LocalInnerClassAppl {
public static Iterator<Object> walkThrough(final Object[] objs) {
class Iter implements Iterator<Object> {
private int pos = 0;
@Override
public boolean hasNext() {
return (pos < objs.length);
}
@Override
public Object next() throws NoSuchElementException {
if (pos >= objs.length)
throw new NoSuchElementException();
return objs[pos++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
return new Iter();
}
public static void main(String[] args) {
Object[] objects = new Object[5];
Iterator<Object> iter = walkThrough(objects);
while (iter.hasNext())
System.out.println(iter.next());
}
}
我的问题是:
当调用iter.hasNext()时,怎么知道objs意味着什么?它未在实例中明确保存。从讨论method-local inner class cannot use variables declared within the method看来,它被隐式复制并保存在iter实例中。你能证实并证实吗?我找不到参考资料。
如果第一个为真(保存了最终参数),那么依赖这种隐式保存是否是一种很好的编程习惯?对不起,如果它是在Java规范中,那么我的第二个Q是无关紧要的,但是再次 - 我没有找到它。
结果是5个null,我将数组的元素保留为未初始化。
答案 0 :(得分:2)
以下是命令
产生的内容javap -private -c LocalInnerClassAppl\$1Iter
-
pkg
是我复制你的类来编译它的包。
Compiled from "LocalInnerClassAppl.java"
class pkg.LocalInnerClassAppl$1Iter extends java.lang.Object implements java.util.Iterator{
private int pos;
private final java.lang.Object[] val$objs;
pkg.LocalInnerClassAppl$1Iter(java.lang.Object[]);
Code:
0: aload_0
1: aload_1
2: putfield #14; //Field val$objs:[Ljava/lang/Object;
5: aload_0
6: invokespecial #16; //Method java/lang/Object."<init>":()V
9: aload_0
10: iconst_0
11: putfield #19; //Field pos:I
14: return
public boolean hasNext();
Code:
0: aload_0
1: getfield #19; //Field pos:I
4: aload_0
5: getfield #14; //Field val$objs:[Ljava/lang/Object;
8: arraylength
9: if_icmpge 14
12: iconst_1
13: ireturn
14: iconst_0
15: ireturn
public java.lang.Object next() throws java.util.NoSuchElementException;
Code:
0: aload_0
1: getfield #19; //Field pos:I
4: aload_0
5: getfield #14; //Field val$objs:[Ljava/lang/Object;
8: arraylength
9: if_icmplt 20
12: new #31; //class java/util/NoSuchElementException
15: dup
16: invokespecial #33; //Method java/util/NoSuchElementException."<init>":()V
19: athrow
20: aload_0
21: getfield #14; //Field val$objs:[Ljava/lang/Object;
24: aload_0
25: dup
26: getfield #19; //Field pos:I
29: dup_x1
30: iconst_1
31: iadd
32: putfield #19; //Field pos:I
35: aaload
36: areturn
public void remove();
Code:
0: new #35; //class java/lang/UnsupportedOperationException
3: dup
4: invokespecial #37; //Method java/lang/UnsupportedOperationException."<init>":()V
7: athrow
}
正如您可以看到编译器生成的字段private final java.lang.Object[] val$objs;
和构造函数LocalInnerClassAppl$1Iter(java.lang.Object[])
。我认为这几乎是第一个问题的答案。
对于第二个问题,它实际上取决于你是否需要多次实例化该类,或者你只是需要实例化它一次并完成它,这取决于你应该决定是否要制作它它本地/匿名。如果它最适合你的情况,那么它很可能是一种很好的做法。
答案 1 :(得分:1)
由于objs
是匿名类的封闭范围中的最终变量,因此它被类“捕获”,其生命周期至少与类一样长。规范并不是那么清楚,但是这条线暗示了它:
通常,任何范围都会继承其父范围;内部类略有不同,因为它只继承其父本地范围的最终成员及其所有封闭类的范围。
这是工厂方法的常见模式,尤其是在处理涉及需要封闭状态的侦听器的异步代码时。