[英]Variable visibility in Java
在下面的代碼中,為什么我不能從另一個線程中看到變量“i”?
public class Main {
public static void main(String[] args) {
int i = 0;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(i);
}
}).start();
}
}
為什么我可以在下面的代碼中看到它?
public class Main {
int i = 0;
public static void main(String[] args) {
new Main().method();
}
private void method() {
new Thread(new Runnable() {
@Override
public void run() {
i = 1;
}
}).start();
}
}
來自docs :
與實例方法和變量一樣,內部類與其封閉類的實例相關聯,並且可以直接訪問該對象的方法和字段。
現在先拿第二個例子,當在父類中聲明i
時,內部類可以訪問它,因為內部類可以訪問整個父對象。 i
正確地從內部類引用為Main.this.i
編譯器秘密地在內部類中this.i
的副本。 this
永遠不會在對象內部發生變化, this.i
將指向內部和外部類的正確對象。 編譯器很高興。
在第一個例子中, i
不是父類的一部分,它在一個方法中聲明,因此它的引用現在在棧上 ,而不是在堆上。 (在這種情況下, i
不會生活在上圖所示的那個大外圓上)。 現在編譯器必須秘密地在內部類中復制i
。 但是害怕方法的i
可能會在堆棧上改變。 編譯器不能在這里使用外部類連接到達i
,並且每次更改時都無法從堆棧中復制i
引用。 因此,它是決定,你必須使該方法的i
參考不變,或者換句話說, final
。
Java播放的模糊秘密技巧,以便您可以從內部類訪問外部字段,詳細解釋如下: http : //techtracer.com/2008/04/14/mystery-of-accessibility-in-local-inner-classes/
並在這里討論了更多“為什么”: http : //people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04044.html
Java僅允許您訪問在匿名類中聲明為final
的局部變量的值。 不允許寫作。 這樣做的理由是因為函數范圍可能(實際上在這種情況下)退出,而變量可以從內部類中訪問,該值實際上是在匿名類實例中緩存的。 為了避免混淆並使JIT工作,這些變量只允許是最終的。 請注意,只能修改原始值或引用,但仍可以修改引用對象中包含的任何內容。
在第二種情況下,它是線程可訪問的實例變量。 請注意, i = 1
現在代表Main.this.i
; Main.this.
部分是隱含的。
在第一個程序中,您可以“查看”變量i
,但不能訪問它,因為它未被聲明為final
。 只能訪問在創建匿名類實例之前聲明的成員變量和final
局部變量:
public class Main {
public static void main(String[] args) {
final int i = 123; // Make the variable final
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(i); // Now it works, but you cannot assign it
}
}).start();
}
}
使變量static
也可以:
public class Main {
private static int i = 321;
public static void main (String[] args) throws java.lang.Exception
{
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(i); // Now it works, but you cannot assign it
}
}).start();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.