![](/img/trans.png)
[英]Why does Java require an explicit cast on a final variable if it was copied from an array?
[英]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());
}
}
我的問題是:
調用iter.hasNext()時,iter如何知道objs的含義? 它沒有顯式保存在實例中。 通過討論, 方法本地內部類無法使用在方法內聲明的變量,因為它看起來像是隱式復制並保存在iter實例中。 您可以確認並證實嗎? 我找不到參考。
如果第一個為真(保存了最后一個參數),那么依靠這種隱式保存是否被視為一種良好的編程習慣? 抱歉,如果它在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
是匿名類的封閉范圍內的最終變量,因此它被該類“捕獲”,並且其生存期至少與該類一樣長。 規格還不是很清楚,但是這一行暗示了這一點:
通常,任何作用域都繼承其父作用域。 內部類稍有不同,因為它僅繼承其父本地范圍的最終成員以及所有其封閉類的范圍。
這是工廠方法的常見模式,尤其是在處理涉及需要封閉狀態的偵聽器的異步代碼時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.