java踩坑記之雙花括號初始化實例導致內存泄露

問題描述

先來看一段代碼:

public class DoubleBracesTest {
    private String key = "key";
    private String value="value";
    public Map<String, String> test(String[] args){
        Map<String, String> map = new HashMap() {{
            put("k", "v");
            put(key,value);
        }};
        return map;
    }
}

通過javac編譯後,生成文件:DoubleBracesTest.class 和 DoubleBracesTest$1.class,確認上面的代碼中的"{{"的方式寫法,採用了內部類來實現的。

用IDEA查看 DoubleBracesTest$1.class :

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.util.HashMap;

class DoubleBracesTest$1 extends HashMap {
    DoubleBracesTest$1(DoubleBracesTest var1) {
        this.this$0 = var1;
        this.put("k", "v");
        this.put(this.this$0.key, this.this$0.value);
    }
}

其中的  this.this$0 = var1  代表內部類持有了外部類的引用。

對應的字節碼:

 

字節碼中的 putfield這一行,這裏表示有一個對DoubleBracesTest的引用被存在了 this$0 中,也就是說它持有了外部類的對象。

test方法返回一個map,如果被其他對象的屬性所引用,GC時便不會回收此對象,從而導致內存泄漏!這個也是非靜態內部類的主要缺點。

非靜態內部類的優點

非靜態匿名內部類持有外部類可以總結爲以下兩個作用 :

1.當匿名內部類只在外部類(主類)中使用時,匿名內部類可以讓外部不知道它的存在,從而減少了代碼的維護工作。

2.當匿名內部類持有外部類時,它就可以直接使用外部類中的變量了,這樣可以很方便的完成調用。

改進方法

1、上述調用方法改成static方法

  匿名內部類是靜態的之後,它所引用的對象或屬性也必須是靜態的了,因此就可以直接從 JVM 的 Method Area(方法區)獲取到引用而無需持久外部對象了,也就不會持有外部類的引用了。

  但是後期難保不會有人將 static 關鍵字刪掉,那樣問題又會出現了!

2

使用集合工廠的 of 方法替代

Map map = new HashMap() {{
    put("k1", "v1");
    put("k2", "v2");
}};
替換成:
Map<String, String> map= Map.of("k1", "v1", "k2", "v2");
 

 

List<String> list = new ArrayList() {{
    add("aaa");
    add("bbb");
}};
替換成:
List<String> list = new ArrayList<String>(Arrays.asList("aaa","bbb"));

Stream API 替代

List<String> list = new ArrayList() {{
    add("aaa");
    add("bbb");
}};
替換成
List<String> list = Stream.of("aaa", "bbb").collect(Collectors.toList());

 

 

參考

https://www.ripjava.com/article/1291630596325408

https://www.cnblogs.com/wenbronk/p/7000643.html

https://cloud.tencent.com/developer/article/1632486

https://cloud.tencent.com/developer/article/1179625

https://hacpai.com/article/1498563483898

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章