簡體   English   中英

將最終參數復制到隱藏變量中?

[英]Final parameters are copied into a hidden variable?

這是從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規范中,那么我的第二個問是無關緊要的,但是再次-我沒有找到它。

結果是5個null,我未初始化數組的元素。

以下是命令產生的結果

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[]) 我認為這基本可以回答第一個問題。

對於第二個問題,它實際上取決於您是否需要多次實例化該類,還是只需要實例化一次並完成該操作,就取決於您決定是否將其設為本地/匿名。 如果最適合您的情況,則很可能是良好的做法。

由於objs是匿名類的封閉范圍內的最終變量,因此它被該類“捕獲”,並且其生存期至少與該類一樣長。 規格還不是很清楚,但是這一行暗示了這一點:

使用的但未在內部類中聲明的任何局部變量,形式參數或異常參數必須聲明為final。

通常,任何作用域都繼承其父作用域。 內部類稍有不同,因為它僅繼承其父本地范圍的最終成員以及所有其封閉類的范圍。

這是工廠方法的常見模式,尤其是在處理涉及需要封閉狀態的偵聽器的異步代碼時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM