0

これは JPL からコピーされたもので (以下のコメントを参照)、インポートと 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 の意味を知ることができますか? インスタンスに明示的に保存されていません。議論から、メソッドローカル内部クラスはメソッド内で宣言された変数を使用できません。暗黙的にコピーされ、反復インスタンスに保存されたようです。それを確認し、証明していただけますか?参照を見つけることができませんでした。

  2. 最初が真 (最後のパラメーターが保存された) の場合、そのような暗黙的な保存に依存することは良いプログラミング手法と見なされますか? それが Java 仕様にある場合は申し訳ありませんが、私の 2 番目の Q は関係ありませんが、やはり見つかりませんでした。

結果は 5 個の null です。配列の要素を初期化せずに残しました。

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[])それは最初の質問にほとんど答えていると思います。

2 番目の質問については、クラスを複数回インスタンス化する必要があるかどうかに大きく依存します。匿名。それがあなたの状況に最も適している場合、それはおそらく良い習慣です。

于 2013-07-02T04:06:43.200 に答える
1

は匿名クラスの外側のスコープ内の最終変数であるためobjs、クラスによって「キャプチャ」され、その有効期間は少なくともクラスと同じくらい長くなります。仕様はそれほど明確ではありませんが、次の行で暗示されています。

内部クラスで宣言されていないローカル変数、仮パラメーター、または例外パラメーターは、final として宣言する必要があります。

一般に、すべてのスコープはその親スコープを継承します。内部クラスは、親のローカル スコープの最終メンバーと、それを囲むクラスのスコープのすべてを継承するだけであるという点で少し異なります。

これは、ファクトリ メソッドの一般的なパターンであり、特に、囲んでいる状態を必要とするリスナーを含む非同期コードを扱う場合に当てはまります。

于 2013-07-02T03:56:20.737 に答える