注意!非靜態內部類和非靜態方法的匿名類的this$0屬性
本文來自圖靈社群 fairjm@ituring 轉截請註明出處
別問我為什麼標題起得那麼長那麼奇怪....
在java中,非靜態內部類和非靜態方法中的匿名類會隱含有一個指向所在外部類例項的this$0
屬性,如果不小心將這些類的例項當作返回值返回,那可能會導致原先的外部類例項無法被垃圾回收(這個引用是隱含的並被洩漏了出去)。
簡單的程式碼展示:
package tmp;
public class Test {
static class InnerClass {
}
class NonStaticInnerClass {
}
public NonStaticInnerClass getInner() {
return new NonStaticInnerClass();
}
public InnerClass getInnerStatic() {
return new InnerClass();
}
public Runnable getAnonymous() {
return new Runnable() {
public void run() {
System.out.println("hello");
}
};
}
public static Runnable getStaticAnonymous() {
return new Runnable() {
public void run() {
System.out.println("hello");
}
};
}
public Runnable getLambda() {
return () -> System.out.println("hello");
}
public static void main(String[] args) {
Test t = new Test();
NonStaticInnerClass inner = t.getInner(); //會有this$0屬性
InnerClass staticInner = t.getInnerStatic();
Runnable ano = t.getAnonymous(); //會有this$0屬性
Runnable anoStatic = Test.getStaticAnonymous();
Runnable lambda = t.getLambda();
}
}
實際debug或者用反射可以看到和註釋一樣的結果。
對於getAnonymous()
方法會產生一個class檔案(當然getStaticAnonymous()
也會產生),名為Test$1.class
。可以檢視下位元組碼的指令,就可以更清楚看到this$0
了(NonStaticInnerClass也類似)
// Compiled from Test.java (version 1.8 : 52.0, super bit)
class tmp.Test$1 implements java.lang.Runnable {
// Field descriptor #8 Ltmp/Test;
final synthetic tmp.Test this$0;
// Method descriptor #10 (Ltmp/Test;)V
// Stack: 2, Locals: 2
Test$1(tmp.Test arg0);
0 aload_0 [this]
1 aload_1 [arg0]
2 putfield tmp.Test$1.this$0 : tmp.Test [12]
5 aload_0 [this]
6 invokespecial java.lang.Object() [14]
9 return
java的lambda可以取代原先的單方法匿名類,可以看到返回值使用lambda並不會導致外部類的例項外洩,看一下位元組碼可以發現使用了invokedynamic
操作:
public java.lang.Runnable getLambda();
0 invokedynamic 0 run() : java.lang.Runnable [38]
5 areturn
關於這個操作 可以看: http://www.javaworld.com/article/2860079/scripting-jvm-languages/invokedynamic-101.html
為什麼我不解釋?因為我也不是很懂... ...就這樣啦~
相關文章
- java之內部類(InnerClass)----非靜態內部類、靜態內部類、區域性內部類、匿名內部類Java
- 靜態內部類和非靜態內部類區別
- 類的靜態屬性和方法
- java內部類,區域性內部類,靜態內部類,匿名內部類Java
- java 非靜態內部類與外部類引用之間的關係Java
- TypeScript 類靜態屬性TypeScript
- net 靜態方法與非靜態方法
- java靜態內部類Java
- 靜態內部類 呼叫
- Delphi 類的靜態屬性 (轉)
- Java中的巢狀類、內部類、靜態內部類Java巢狀
- 深入理解JavaScript類與物件:揭秘類欄位和靜態屬性的妙用,js靜態屬性和例項屬性JavaScript物件JS
- PHP 中 static 靜態屬性和靜態方法的呼叫PHP
- 靜態變數和非靜態變數變數
- JavaScript 靜態屬性與靜態方法JavaScript
- PHP類的靜態(static)方法和靜態(static)變數PHP變數
- wpf xaml binding靜態類的屬性
- Java中的靜態內部類詳解Java
- 區域性變數和全域性變數(靜態和非靜態)區別變數
- 物件導向2--靜態方法、類方法、屬性方法物件
- [譯] 繼承 JavaScript 類中的靜態屬性繼承JavaScript
- Effective Java 3rd 條目24 靜態成員類優於非靜態Java
- Java中靜態跟非靜態的區別總結Java
- js 物件方法、類方法、原型方法的區別;私有屬性、公有屬性、公有靜態屬性的區別JS物件原型
- Python 靜態方法和類方法的區別Python
- Python的靜態方法和類成員方法Python
- 靜態屬性
- 類內的靜態成員函式函式
- JavaScript私有屬性和靜態屬性JavaScript
- Object C學習筆記10-靜態方法和靜態屬性Object筆記
- Java內部類和匿名內部類的用法Java
- c#物件導向- 靜態成員和非靜態成員的區別C#物件
- 靜態方法查詢類名
- c# 非靜態欄位、方法或屬性要求物件引用C#物件
- 關於php中靜態方法,靜態屬性的一些淺見PHP
- Delphi系列談之:Delphi中的靜態屬性及靜態方法的實現 (轉)
- Java 反射修改類的常量值、靜態變數值、屬性值Java反射變數
- Java的靜態成員類Java