0

这是从 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());
    }
}

我的问题是:

  1. 当调用 iter.hasNext() 时,iter 怎么知道 objs 是什么意思?它没有明确保存在实例中。从讨论方法局部内部类不能使用在方法中声明的变量,它看起来像是被隐式复制并保存在 iter 实例中。你能证实和证实吗?我没有找到参考。

  2. 如果第一个为真(保存了最终参数),那么依赖这种隐式保存是否被认为是一种好的编程习惯?抱歉,如果它在 Java 规范中,那么我的第二个 Q 是无关紧要的,但同样 - 我没有找到它。

结果是 5 个空值,我未初始化数组的元素。

4

2 回答 2

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[])我认为这几乎回答了第一个问题。

对于第二个问题,它实际上取决于您是否需要多次实例化该类,或者您是否只需要实例化一次并完成它,这取决于您是否应该决定是否将其设为本地/匿名的。如果它最适合您的情况,那么它很可能是一种好的做法。

于 2013-07-02T04:06:43.200 回答
1

由于objs它是匿名类封闭范围内的最终变量,因此它被类“捕获”,并且它的生命周期至少与类一样长。规范不是那么清楚,但它暗示了这一行:

任何使用但未在内部类中声明的局部变量、形参或异常参数都必须声明为 final。

一般来说,任何作用域都继承其父作用域;内部类略有不同,因为它只继承其父本地范围的最终成员,以及它的所有封闭类的范围。

这是工厂方法的常见模式,尤其是在处理涉及需要封闭状态的侦听器的异步代码时。

于 2013-07-02T03:56:20.737 回答