最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何避免在Java?中使用雙括號(hào)初始化

 更新時(shí)間:2023年07月17日 10:20:46   作者:明明如月學(xué)長(zhǎng)  
這篇文章主要介紹了如何避免在Java中使用雙括號(hào)初始化,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

結(jié)論先行

避免像這樣,在 Java 中使用雙括號(hào)初始化:

new HashMap<String, String>() {{
     put("key", value);
}};

內(nèi)存泄漏追蹤

我最近正在 LeakCanary 看到了以下內(nèi)存泄漏追蹤信息:

┬───
│ GC Root: Global variable in native code
│
├─ com.bugsnag.android.AnrPlugin instance
│   Leaking: UNKNOWN
│   ↓ AnrPlugin.client
│               ~~~~~~
├─ com.bugsnag.android.Client instance
│   Leaking: UNKNOWN
│   ↓ Client.breadcrumbState
│               ~~~~~~~~~~~~~~~
├─ com.bugsnag.android.BreadcrumbState instance
│   Leaking: UNKNOWN
│   ↓ BreadcrumbState.store
│                       ~~~~~
├─ com.bugsnag.android.Breadcrumb[] array
│   Leaking: UNKNOWN
│   ↓ Breadcrumb[494]
│               ~~~~~
├─ com.bugsnag.android.Breadcrumb instance
│   Leaking: UNKNOWN
│   ↓ Breadcrumb.impl
│                   ~~~~
├─ com.bugsnag.android.BreadcrumbInternal instance
│   Leaking: UNKNOWN
│   ↓ BreadcrumbInternal.metadata
│                           ~~~~~~~~
├─ com.example.MainActivity$1 instance
│   Leaking: UNKNOWN
│   Anonymous subclass of java.util.HashMap
│   ↓ MainActivity$1.this$0
│                       ~~~~~~
╰→ com.example.MainActivity instance
    Leaking: YES (Activity#mDestroyed is true)

當(dāng)打開(kāi)一個(gè)內(nèi)存泄漏追蹤日志時(shí),我首先會(huì)看底部的對(duì)象,了解它的生命周期,這將幫助我理解內(nèi)存泄漏追蹤中的其他對(duì)象是否應(yīng)該有相同的生命周期。

在底部,我們看到:

╰→ com.example.MainActivity instance
    Leaking: YES (Activity#mDestroyed is true)

Activity 已經(jīng)被銷毀,應(yīng)該已被垃圾回收器給回收掉了,但它仍駐留在內(nèi)存中。

此時(shí),我開(kāi)始在內(nèi)存泄漏追蹤日志中尋找已知類型,并嘗試弄清楚它們是否屬于同一個(gè)被銷毀的范圍(=> 正在泄漏)或更高的范圍(=> 沒(méi)有泄漏)。

在頂部,我們看到:

├─ com.bugsnag.android.Client instance
│   Leaking: UNKNOWN

我們的 BugSnag 客戶端是一個(gè)用于分析崩潰報(bào)告單例,由于每個(gè)應(yīng)用我們創(chuàng)建一個(gè)實(shí)例,所以它沒(méi)有泄漏。

├─ com.bugsnag.android.Client instance
│   Leaking: NO

所以我們現(xiàn)在需要轉(zhuǎn)變焦點(diǎn),特別關(guān)注從最后一個(gè) Leaking: NO 到第一個(gè) Leaking: YES 的部分:

…
├─ com.bugsnag.android.Client instance
│   Leaking: NO
│   ↓ Client.breadcrumbState
│               ~~~~~~~~~~~~~~~
├─ com.bugsnag.android.BreadcrumbState instance
│   Leaking: UNKNOWN
│   ↓ BreadcrumbState.store
│                       ~~~~~
├─ com.bugsnag.android.Breadcrumb[] array
│   Leaking: UNKNOWN
│   ↓ Breadcrumb[494]
│               ~~~~~
├─ com.bugsnag.android.Breadcrumb instance
│   Leaking: UNKNOWN
│   ↓ Breadcrumb.impl
│                   ~~~~
├─ com.bugsnag.android.BreadcrumbInternal instance
│   Leaking: UNKNOWN
│   ↓ BreadcrumbInternal.metadata
│                           ~~~~~~~~
├─ com.example.MainActivity$1 instance
│   Leaking: UNKNOWN
│   Anonymous subclass of java.util.HashMap
│   ↓ MainActivity$1.this$0
│                       ~~~~~~
╰→ com.example.MainActivity instance
    Leaking: YES (Activity#mDestroyed is true)

BugSnag 客戶端保持了一個(gè)面包屑的環(huán)形緩沖區(qū)。這些應(yīng)該保留在內(nèi)存中,它們也沒(méi)有泄漏。

所以讓我們跳過(guò)上述內(nèi)容,從下面這里繼續(xù)分析:

├─ com.bugsnag.android.BreadcrumbInternal instance
│   Leaking: NO

我們只需要關(guān)注從最后一個(gè) Leaking: NO 到第一個(gè)Leaking: YES 的部分:

…
├─ com.bugsnag.android.BreadcrumbInternal instance
│   Leaking: NO
│   ↓ BreadcrumbInternal.metadata
│                           ~~~~~~~~
├─ com.example.MainActivity$1 instance
│   Leaking: UNKNOWN
│   Anonymous subclass of java.util.HashMap
│   ↓ MainActivity$1.this$0
│                       ~~~~~~
╰→ com.example.MainActivity instance
    Leaking: YES (Activity#mDestroyed is true)
  • BreadcrumbInternal.metadata :內(nèi)存泄漏追蹤通過(guò)面包屑實(shí)現(xiàn)的元數(shù)據(jù)字段。
  • MainActivity$1 實(shí)例是 java.util.HashMap 的匿名子類:MainActivity$1 是在MainActivity 中定義的 HashMap 的匿名子類。它是從 MainActivity.java 中定義的第一個(gè)匿名類(因?yàn)槭?$1 )。
  • this$0:每個(gè)匿名類都有一個(gè)隱式字段引用到定義它的外部類,這個(gè)字段被命名為 this$0 。

也就是說(shuō):記錄到 BugSnag 的面包屑之一有一個(gè)元數(shù)據(jù)映射,這是一個(gè) HashMap 的匿名子類 ,它保留對(duì)外部類的引用,這個(gè)外部類就是被銷毀的 Activity 。

讓我們看看我們?cè)?MainActivity 中記錄面包屑的地方:

void logSavingTicket(String ticketId) {
    Map<String, Object> metadata = new HashMap<String, Object>() {{
      put("ticketId", ticketId);
    }};
    bugsnagClient.leaveBreadcrumb("Saving Ticket", metadata, LOG);
}

這段代碼利用了一個(gè)被稱為“雙括號(hào)初始化” 的有趣的 Java 代碼塊 。它允許你創(chuàng)建一個(gè) HashMap,并通過(guò)添加代碼到 HashMap 的匿名子類的構(gòu)造函數(shù)中同時(shí)初始化它。

new HashMap<String, Object>() {{
  	put("ticketId", ticketId);
}};

Java 的匿名類總是隱式地引用其外部類。

因此,這段代碼:

void logSavingTicket(String ticketId) {
    Map<String, Object> metadata = new HashMap<String, Object>() {{
      put("ticketId", ticketId);
    }};
    bugsnagClient.leaveBreadcrumb("Saving Ticket", metadata, LOG);
}

實(shí)際上被編譯為:

class MainActivity$1 extends HashMap<String, Object> {
  private final MainActivity this$1;
  MainActivity$1(MainActivity this$1, String ticketId) {
     this.this$1 = this$1;
     put("ticketId", ticketId);
  }
}
void logSavingTicket(String ticketId) {
  Map<String, Object> metadata = new MainActivity$1(this, ticketId);
  bugsnagClient.leaveBreadcrumb("Saving Ticket", metadata, LOG);
}

結(jié)果,這個(gè) breadcrumb 就一直持有對(duì)已銷毀的 activity 實(shí)例的引用。

總結(jié)

盡管使用 Java 的雙括號(hào)初始化看起來(lái)很"炫酷",但它會(huì)無(wú)故地額外創(chuàng)建類,可能會(huì)導(dǎo)致內(nèi)存泄漏。因此避免在 Java 中使用雙括號(hào)初始化。

你可以用下面這種更安全的方式來(lái)解決這個(gè)問(wèn)題:

Map<String, Object> metadata = new HashMap<>();
metadata.put("ticketId", ticketId);
bugsnagClient.leaveBreadcrumb("Saving Ticket", metadata, LOG);

或者利用 Collections.singletonMap() 進(jìn)一步簡(jiǎn)化代碼:

Map<String, Object> metadata = singletonMap("ticketId", ticketId);
bugsnagClient.leaveBreadcrumb("Saving Ticket", metadata, LOG);

或者,直接將文件轉(zhuǎn)換為 Kotlin。

到此這篇關(guān)于如何避免在Java 中使用雙括號(hào)初始化的文章就介紹到這了,更多相關(guān)java雙括號(hào)初始化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis中的@SelectProvider注解源碼分析

    MyBatis中的@SelectProvider注解源碼分析

    這篇文章主要介紹了MyBatis中的@SelectProvider注解源碼分析,@SelectProvider功能就是用來(lái)單獨(dú)寫(xiě)一個(gè)class類與方法,用來(lái)提供一些xml或者注解中不好寫(xiě)的sql,今天就來(lái)說(shuō)下這個(gè)注解的具體用法與源碼,需要的朋友可以參考下
    2024-01-01
  • spring boot 3.3.0和mybatis plus 3.5.6版本沖突的問(wèn)題解決

    spring boot 3.3.0和mybatis plus 3.5.6版本沖突

    這篇文章主要介紹了spring boot 3.3.0和mybatis plus 3.5.6版本沖突的問(wèn)題解決,文中介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • Java日期時(shí)間與正則表達(dá)式超詳細(xì)整理(適合新手入門)

    Java日期時(shí)間與正則表達(dá)式超詳細(xì)整理(適合新手入門)

    如果使用得當(dāng),正則表達(dá)式是匹配各種模式的強(qiáng)大工具,下面這篇文章主要給大家介紹了關(guān)于Java日期時(shí)間與正則表達(dá)式超詳細(xì)整理的相關(guān)資料,本文非常適合新手入門,需要的朋友可以參考下
    2023-04-04
  • Java實(shí)現(xiàn)預(yù)覽與打印功能詳解

    Java實(shí)現(xiàn)預(yù)覽與打印功能詳解

    在?Java?中,打印功能主要依賴?java.awt.print?包,該包提供了與打印相關(guān)的一些關(guān)鍵類,比如?PrinterJob?和?PageFormat,它們構(gòu)成了?Java?打印框架的核心,接下來(lái)我們將一步步實(shí)現(xiàn)一個(gè)簡(jiǎn)單的預(yù)覽和打印功能,需要的朋友可以參考下
    2025-07-07
  • 分布式Netty源碼分析EventLoopGroup及介紹

    分布式Netty源碼分析EventLoopGroup及介紹

    這篇文章主要介紹了分布式Netty源碼分析EventLoopGroup及介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • idea常用習(xí)慣操作設(shè)置方法圖解

    idea常用習(xí)慣操作設(shè)置方法圖解

    這篇文章主要介紹了idea常用習(xí)慣操作設(shè)置方法,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • SpringBoot各種注解詳解

    SpringBoot各種注解詳解

    SpringBoot的一個(gè)核心功能是IOC,就是將Bean初始化加載到容器中,Bean是如何加載到容器的,可以使用SpringBoot注解方式或者Spring XML配置方式。SpringBoot注解方式減少了配置文件內(nèi)容,更加便于管理,并且使用注解可以大大提高了開(kāi)發(fā)效率
    2022-12-12
  • Shiro + JWT + SpringBoot應(yīng)用示例代碼詳解

    Shiro + JWT + SpringBoot應(yīng)用示例代碼詳解

    這篇文章主要介紹了Shiro (Shiro + JWT + SpringBoot應(yīng)用),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • java中ReentrantLock實(shí)現(xiàn)公平鎖和非公平鎖

    java中ReentrantLock實(shí)現(xiàn)公平鎖和非公平鎖

    在Java里,公平鎖和非公平鎖是多線程編程中用于同步的兩種鎖機(jī)制,它們的主要差異在于獲取鎖的順序規(guī)則,下面就來(lái)詳細(xì)的介紹一下,感興趣的可以了解一下
    2025-12-12
  • spring裝配bean的3種方式總結(jié)

    spring裝配bean的3種方式總結(jié)

    這篇文章主要給大家介紹了關(guān)于spring裝配bean的3種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論

阿巴嘎旗| 隆昌县| 万盛区| 嘉义市| 东丽区| 内乡县| 科尔| 七台河市| 呼玛县| 泾川县| 台中市| 淮安市| 龙口市| 阳东县| 尼木县| 林周县| 高安市| 神农架林区| 德安县| 镇雄县| 铜梁县| 临安市| 赞皇县| 大化| 台东县| 当雄县| 大渡口区| 双柏县| 桓台县| 河北区| 湖口县| 尼木县| 湖州市| 林芝县| 普陀区| 浪卡子县| 平原县| 梁河县| 休宁县| 尼勒克县| 江山市|