电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Java內(nèi)部類(lèi)的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說(shuō)明

瀏覽:41日期:2022-08-23 11:05:34

在使用java內(nèi)部類(lèi)的時(shí)候要注意可能引起的內(nèi)存泄漏

代碼如下

package com.example;public class MyClass { public static void main(String[] args) throws Throwable { } public class A{ public void methed1(){ } } public static class B{ public void methed1(){ } }

編譯生成了如下文件

Java內(nèi)部類(lèi)的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說(shuō)明

反編譯MyClass

Java內(nèi)部類(lèi)的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說(shuō)明

反編譯MyClassA

Java內(nèi)部類(lèi)的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說(shuō)明

反編譯GlassB

Java內(nèi)部類(lèi)的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說(shuō)明

從反編譯的結(jié)果可以知道,內(nèi)部類(lèi)的實(shí)現(xiàn)其實(shí)是通過(guò)編譯器的語(yǔ)法糖實(shí)現(xiàn)的,通過(guò)生成相應(yīng)的子類(lèi)即以O(shè)utClassName$InteriorClassName命名的Class文件。

并添加構(gòu)造函數(shù),在構(gòu)造函數(shù)中傳入外部類(lèi),這也是為什么內(nèi)部類(lèi)能使用外部類(lèi)的方法與字段的原因。

我們明白了這個(gè)也就要小心,當(dāng)外部類(lèi)與內(nèi)部類(lèi)生命周期不一致的時(shí)候很有可能發(fā)生內(nèi)存泄漏,例如在一個(gè)Activity啟動(dòng)一個(gè)Thread執(zhí)行一個(gè)任務(wù),因?yàn)門(mén)hread是內(nèi)部類(lèi)持有了Activity的引用,當(dāng)Activity銷(xiāo)毀的時(shí)候如果Thread的任務(wù)沒(méi)有執(zhí)行完成,造成Activity的引用不能釋放,Activity不能被釋放而引起了內(nèi)存泄漏。

這種情況下可以通過(guò)聲明一個(gè)static的內(nèi)部類(lèi)來(lái)解決問(wèn)題,從反編譯中可以看出,聲明為static的類(lèi)不會(huì)持有外部類(lèi)的引用,如果你想使用外部類(lèi)的話,可以通過(guò)軟引用的方式保存外部類(lèi)的引用。

具體的代碼就不上了。

補(bǔ)充知識(shí):Java內(nèi)部類(lèi)的底層實(shí)現(xiàn)原理

摘要:

定義:在一個(gè)類(lèi)中創(chuàng)建另一個(gè)類(lèi),叫做成員內(nèi)部類(lèi),這個(gè)內(nèi)部類(lèi)可以是靜態(tài)的,也可以是非靜態(tài)的。

已知靜態(tài)內(nèi)部類(lèi)的應(yīng)用(可以解決的問(wèn)題):

通過(guò)內(nèi)部類(lèi)解決java 的單繼承問(wèn)題,外部類(lèi)不能同時(shí)繼承的類(lèi)可以交給內(nèi)部類(lèi)繼承

設(shè)計(jì)模式中,builder 模式通過(guò)定義一個(gè)靜態(tài)內(nèi)部類(lèi)實(shí)現(xiàn)

類(lèi)型匯總:

靜態(tài)內(nèi)部類(lèi)

成員內(nèi)部類(lèi)

方法內(nèi)部類(lèi)

匿名內(nèi)部類(lèi)

一、靜態(tài)內(nèi)部類(lèi)

靜態(tài)內(nèi)部類(lèi)的定義和普通的靜態(tài)變量或者靜態(tài)方法的定義方法是一樣的,使用static關(guān)鍵字,只不過(guò)這次static是修飾在class上的,一般而言,只有靜態(tài)內(nèi)部類(lèi)才允許使用static關(guān)鍵字修飾,普通類(lèi)的定義是不能用static關(guān)鍵字修飾的,這一點(diǎn)需要注意一下。下面定義一個(gè)靜態(tài)內(nèi)部類(lèi):

public class Out { private static String name; private int age; public static class In{ private int age; public void sayHello(){ System.out.println('my name is : '+name); //--編譯報(bào)錯(cuò)--- //System.out.println('my age is :'+ age); } }}

在上述代碼中,In這個(gè)類(lèi)就是一個(gè)靜態(tài)內(nèi)部類(lèi)。我們說(shuō)內(nèi)部類(lèi)是可以訪問(wèn)外部類(lèi)的私有字段和私有方法的,對(duì)于靜態(tài)內(nèi)部類(lèi),它遵循一致的原則,只能訪問(wèn)外部類(lèi)的靜態(tài)成員。上述代碼中,外部類(lèi)的非靜態(tài)私有字段age在靜態(tài)內(nèi)部類(lèi)中使不允許訪問(wèn)的,而靜態(tài)字段name則是可訪問(wèn)的。下面我們看,如何創(chuàng)建一個(gè)靜態(tài)內(nèi)部類(lèi)的實(shí)例對(duì)象。

public static void main(String [] args){ Out.In innerClass = new Out.In(); innerClass.sayHello();}

靜態(tài)內(nèi)部類(lèi)的實(shí)例對(duì)象創(chuàng)建還是比較簡(jiǎn)潔的,不同于成員內(nèi)部類(lèi),它不需要關(guān)聯(lián)外部類(lèi)實(shí)例(具體的下文介紹),下面我們?cè)倏匆欢未a:

public class Out { private static String name; public static class In{ public void sayHello(){ System.out.println(name); showName(); } } private static void showName(){ System.out.println(name); }}

上述代碼在內(nèi)部類(lèi)中兩次訪問(wèn)了外部類(lèi)的靜態(tài)成員,第一次訪問(wèn)了靜態(tài)字段name,第二次訪問(wèn)的靜態(tài)方法showName。在我們反編譯這個(gè)類(lèi)之前,首先需要知道的是,所謂的內(nèi)部類(lèi)的概念只是出現(xiàn)在編譯階段,對(duì)于jvm層是沒(méi)有內(nèi)部類(lèi)這個(gè)概念的。也就是說(shuō),編譯器會(huì)將一個(gè)類(lèi)編譯成一個(gè)源文件,對(duì)于內(nèi)部類(lèi)也是一樣,它會(huì)從它的外部類(lèi)中抽離出來(lái),增加一些與外部類(lèi)的聯(lián)系,然后被編譯成一個(gè)單獨(dú)的源文件。下面我們先編譯運(yùn)行之后,利用Dj反編譯class文件看看編譯器都做了些什么事情。

//這是我們的Out外部類(lèi)public class Out{ //省去了一些不重要的部分 private static void showName() { System.out.println(name); } private static String name; static String access$000(){return name;} static void access$100(){showName();} }//這是我們的內(nèi)部類(lèi)public static class Out$In{ public void sayHello() { System.out.println(Out.access$000()); Out.access$100(); } public Out$In() { }}

相信大家也已經(jīng)看出來(lái)這兩者之間的某種聯(lián)系,編譯器將Out這個(gè)類(lèi)編譯成兩個(gè)獨(dú)立的class源文件。對(duì)于Out中所有的私有成員(也就是內(nèi)部類(lèi)分離出去之后不能訪問(wèn)的成員),增設(shè)了可供調(diào)用的access$xxx方法,從而實(shí)現(xiàn)內(nèi)部類(lèi)與外部類(lèi)之間的聯(lián)系。這就是他們的本質(zhì)。

至于使用場(chǎng)景,一般來(lái)說(shuō),對(duì)于和外部類(lèi)聯(lián)系緊密但是并不依賴(lài)于外部類(lèi)實(shí)例的情況下,可以考慮定義成靜態(tài)內(nèi)部類(lèi)。下面我們看稍顯復(fù)雜的成員內(nèi)部類(lèi)。

二、成員內(nèi)部類(lèi)

我們說(shuō)了,四種不同類(lèi)型的內(nèi)部類(lèi)都各自有各自的使用場(chǎng)景,靜態(tài)內(nèi)部類(lèi)適合于那種和外部類(lèi)關(guān)系密切但是并不依賴(lài)外部類(lèi)實(shí)例的情況。但是對(duì)于需要和外部類(lèi)實(shí)例相關(guān)聯(lián)的情況下,可以選擇將內(nèi)部類(lèi)定義成成員內(nèi)部類(lèi)。以下代碼定義了一個(gè)簡(jiǎn)單的成員內(nèi)部類(lèi):

public class Out { private String name; public void showName(){ System.out.println('my name is : '+name); } public class In{ public void sayHello(){ System.out.println(name); Out.this.showName(); } }}

以上定義了一個(gè)簡(jiǎn)單的內(nèi)部類(lèi)In,我們的成員內(nèi)部類(lèi)可以直接訪問(wèn)外部類(lèi)的成員字段和成員方法,因?yàn)樗顷P(guān)聯(lián)著一個(gè)外部類(lèi)實(shí)例的。下面我們看看在外部是如何創(chuàng)建該內(nèi)部類(lèi)實(shí)例的。

public static void main(String [] args){ Out out = new Out(); Out.In in = out.new In(); in.sayHello();}

因?yàn)槌蓡T內(nèi)部類(lèi)是關(guān)聯(lián)著一個(gè)具體的外部類(lèi)實(shí)例的,所以它的實(shí)例創(chuàng)建必然是由外部類(lèi)實(shí)例來(lái)創(chuàng)建的。對(duì)于實(shí)例的創(chuàng)建,我們只需要記住即可,成員內(nèi)部類(lèi)的實(shí)例創(chuàng)建需要關(guān)聯(lián)外部類(lèi)實(shí)例對(duì)象,靜態(tài)內(nèi)部類(lèi)實(shí)例創(chuàng)建相對(duì)簡(jiǎn)單。下面我們主要看看在編譯階段編譯器是如何保持內(nèi)部類(lèi)對(duì)外部類(lèi)成員信息可訪問(wèn)的。

//反編譯的Out外部類(lèi)源碼public class Out{ //省略部分非核心代碼 public void showName() { System.out.println((new StringBuilder()).append('my name is : ').append(name).toString()); } private String name; static String access$000(Out o){return o.name;}}//反編譯的內(nèi)部類(lèi)In源碼public class Out$In{ public void sayHello() { System.out.println(Out.access$000(Out.this)); showName(); } final Out this$0; public Out$In() { this.this$0 = Out.this; super(); }}

由上述代碼其實(shí)我們可以知道,當(dāng)我們利用外部類(lèi)實(shí)例創(chuàng)建內(nèi)部類(lèi)實(shí)例的時(shí)候,會(huì)將外部類(lèi)實(shí)例作為初始資源傳入內(nèi)部類(lèi)構(gòu)造過(guò)程。這樣我們就可以通過(guò)該實(shí)例訪問(wèn)外部類(lèi)所有的成員信息,包括私有成員。(顯式增加了暴露方法)

至于使用場(chǎng)景,對(duì)于那種要高度依賴(lài)外部類(lèi)實(shí)例的情況下,定義一個(gè)成員內(nèi)部類(lèi)則會(huì)顯的更加明智。

三、方法內(nèi)部類(lèi)

方法內(nèi)部類(lèi),顧名思義,定義在一個(gè)方法內(nèi)部的類(lèi)。方法內(nèi)部類(lèi)相對(duì)而言要復(fù)雜一些,下面定義一個(gè)方法內(nèi)部類(lèi):

public class Out { private String name; public void sayHello(){ class In{ public void showName(){System.out.println('my name is : '+name); } } In in = new In(); in.showName(); }}

我們定義了一個(gè)類(lèi),在該類(lèi)中又定義了一個(gè)方法sayHello,然而在該方法中我們定義了一個(gè)內(nèi)部類(lèi),類(lèi)In就是一個(gè)方法內(nèi)部類(lèi)。我們的方法內(nèi)部類(lèi)的生命周期不超過(guò)包含它的方法的生命周期,也就是說(shuō),方法內(nèi)部類(lèi)只能在方法中使用。所以在聲明的時(shí)候,任何的訪問(wèn)修飾符都是沒(méi)有意義的,于是Java干脆不允許使用任何的訪問(wèn)修飾符修飾方法內(nèi)部類(lèi)。其中還需要注意一點(diǎn)的是,定義和使用時(shí)兩回事,別看那一大串定義類(lèi)的代碼,你實(shí)際想要使用該類(lèi),就必須new對(duì)象,而對(duì)于方法內(nèi)部類(lèi)而言,只能在方法內(nèi)部new對(duì)象。這就是方法內(nèi)部類(lèi)的簡(jiǎn)單介紹,下面我們看看其實(shí)現(xiàn)原理。

有關(guān)方法內(nèi)部類(lèi)的實(shí)現(xiàn)原理其實(shí)是和成員內(nèi)部類(lèi)差不太多的,也是在內(nèi)部類(lèi)初始化的時(shí)候?yàn)槠鋫魅胍粋€(gè)外部類(lèi)實(shí)例,區(qū)別在哪呢?就在于方法內(nèi)部類(lèi)是定義在具體方法的內(nèi)部的,所以該類(lèi)除了可以通過(guò)傳入的外部實(shí)例訪問(wèn)外部類(lèi)中的字段和方法,對(duì)于包含它的方法中被傳入的參數(shù)也會(huì)隨著外部類(lèi)實(shí)例一起初始化給內(nèi)部類(lèi)。

毋庸置疑的是,方法內(nèi)部類(lèi)的封裝性比之前介紹的兩種都要完善。所以一般只有在需要高度封裝的時(shí)候才會(huì)將類(lèi)定義成方法內(nèi)部類(lèi)。

四、匿名內(nèi)部類(lèi)

可能內(nèi)部類(lèi)的所有分類(lèi)中,匿名內(nèi)部類(lèi)的名號(hào)是最大的,也是我們最常用到的,多見(jiàn)于函數(shù)式編程,lambda表達(dá)式等。下面我們重點(diǎn)看看這個(gè)匿名內(nèi)部類(lèi)。

匿名內(nèi)部類(lèi)就是沒(méi)有名字的內(nèi)部類(lèi),在定義完成同時(shí),實(shí)例也創(chuàng)建好了,常常和new關(guān)鍵字緊密結(jié)合。當(dāng)然,它也不局限于類(lèi),也可以是接口 ,可以出現(xiàn)在任何位置。下面我們定義一個(gè)匿名內(nèi)部類(lèi):

//首先定義一個(gè)普通類(lèi)public class Out { private String name; private void sayHello(){ System.out.println('my name is :' + name); }}//定義和使用一個(gè)匿名內(nèi)部類(lèi)public static void main(String [] args){ Out out = new Out(){ @Override public void sayHello(){ System.out.println('my name is cyy'); } public void showName(){ System.out.println('hello single'); } }; out.sayHello();}

從上述代碼中可以很顯然的讓我們看出來(lái),我們的匿名內(nèi)部類(lèi)必定是要依托一個(gè)父類(lèi)的,因?yàn)樗菦](méi)有名字的,無(wú)法用一個(gè)具體的類(lèi)型來(lái)表示。所以匿名內(nèi)部類(lèi)往往都是通過(guò)繼承一個(gè)父類(lèi),重寫(xiě)或者重新聲明一些成員來(lái)實(shí)現(xiàn)一個(gè)匿名內(nèi)部類(lèi)的定義。實(shí)際上還是利用了里式轉(zhuǎn)換原理。

從中我們也可以看到,一個(gè)匿名內(nèi)部類(lèi)定義的完成就意味著該內(nèi)部類(lèi)實(shí)例創(chuàng)建的完成。下面我們看看其實(shí)現(xiàn)原理:

//反編譯出來(lái)的匿名內(nèi)部類(lèi)static class Test$1 extends Out{ Out out; public void sayHello() { System.out.println('my name is cyy'); } Test$1(Out o) { this.out = o; }}

其實(shí)在看了上述三種內(nèi)部類(lèi)的原理之后,反而覺(jué)得匿名內(nèi)部類(lèi)的實(shí)現(xiàn)較為簡(jiǎn)單了。主要思路還是將內(nèi)部類(lèi)抽離出來(lái),通過(guò)初始化傳入外部類(lèi)的實(shí)例以達(dá)到對(duì)外部類(lèi)所有成員的訪問(wèn)。只是在匿名內(nèi)部類(lèi)中,被依托的父類(lèi)不是他的外部類(lèi)。匿名內(nèi)部類(lèi)的主要特點(diǎn)在于,沒(méi)有名字,對(duì)象只能被使用一次,可以出現(xiàn)在任意位置。所以它的使用場(chǎng)景也是呼之欲出,對(duì)于一些對(duì)代碼簡(jiǎn)潔度有所要求的情況下,可首選匿名內(nèi)部類(lèi)。

以上完成了對(duì)四種內(nèi)部類(lèi)的簡(jiǎn)單介紹,對(duì)于他們各自實(shí)現(xiàn)的原理也都已經(jīng)介紹過(guò)了。其實(shí)大致相同,由于jvm對(duì)每個(gè)類(lèi)都要求一個(gè)單獨(dú)的源碼文件,所以編譯階段就完成了分離的操作,但是在分離的過(guò)程中又要保持內(nèi)部類(lèi)和外部類(lèi)之間的這種聯(lián)系,于是編譯器添加了一些接口保持這種信息共享的結(jié)構(gòu)。使用內(nèi)部類(lèi)可以大大增加程序的封裝性,使得代碼整體簡(jiǎn)潔度較高。

以上這篇Java內(nèi)部類(lèi)的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說(shuō)明就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 大白菜官网,大白菜winpe,大白菜U盘装系统, u盘启动盘制作工具 | 玻纤土工格栅_钢塑格栅_PP焊接_单双向塑料土工格栅_复合防裂布厂家_山东大庚工程材料科技有限公司 | 釜溪印象网络 - Powered by Discuz!| 安徽成考网-安徽成人高考网| 水质监测站_水质在线分析仪_水质自动监测系统_多参数水质在线监测仪_水质传感器-山东万象环境科技有限公司 | 影合社-影视人的内容合作平台 | 恒温油槽-恒温水槽-低温恒温槽厂家-宁波科麦仪器有限公司 | 长沙中央空调维修,中央空调清洗维保,空气能热水工程,价格,公司就找维小保-湖南维小保环保科技有限公司 | 华东师范大学在职研究生招生网_在职研究生招生联展网 | 万濠影像仪(万濠投影仪)百科-苏州林泽仪器 | 连续油炸机,全自动油炸机,花生米油炸机-烟台茂源食品机械制造有限公司 | 西点培训学校_法式西点培训班_西点师培训_西点蛋糕培训-广州烘趣西点烘焙培训学院 | 皮带式输送机械|链板式输送机|不锈钢输送机|网带输送机械设备——青岛鸿儒机械有限公司 | 阀门智能定位器_电液动执行器_气动执行机构-赫尔法流体技术(北京)有限公司 | 【德信自动化】点胶机_全自动点胶机_自动点胶机厂家_塑料热压机_自动螺丝机-深圳市德信自动化设备有限公司 | 清水混凝土修复_混凝土色差修复剂_混凝土色差调整剂_清水混凝土色差修复_河南天工 | 变色龙云 - 打包app_原生app_在线制作平台_短链接_ip查询 | 横河变送器-横河压力变送器-EJA变送器-EJA压力变送器-「泉蕴仪表」 | 萃取箱-萃取槽-PVC萃取箱厂家-混合澄清槽- 杭州南方化工设备 | 水稻烘干机,小麦烘干机,大豆烘干机,玉米烘干机,粮食烘干机_巩义市锦华粮食烘干机械制造有限公司 水环真空泵厂家,2bv真空泵,2be真空泵-淄博真空设备厂 | 桂林腻子粉_内墙外墙抗裂砂浆腻子粉推荐广西鑫达涂料厂家供应 | 鄂泉泵业官网|(杭州、上海、全国畅销)大流量防汛排涝泵-LW立式排污泵 | 大功率金属激光焊接机价格_不锈钢汽车配件|光纤自动激光焊接机设备-东莞市正信激光科技有限公司 定制奶茶纸杯_定制豆浆杯_广东纸杯厂_[绿保佳]一家专业生产纸杯碗的厂家 | 食药成分检测_调料配方还原_洗涤剂化学成分分析_饲料_百检信息科技有限公司 | 仿古建筑设计-仿古建筑施工-仿古建筑公司-汉匠古建筑设计院 | 油冷式_微型_TDY电动滚筒_外装_外置式电动滚筒厂家-淄博秉泓机械有限公司 | PCB设计,PCB抄板,电路板打样,PCBA加工-深圳市宏力捷电子有限公司 | 深圳货架厂家_金丽声精品货架_广东金丽声展示设备有限公司官网 | 探伤仪,漆膜厚度测试仪,轮胎花纹深度尺厂家-淄博创宇电子 | 半自动预灌装机,卡式瓶灌装机,注射器灌装机,给药器灌装机,大输液灌装机,西林瓶灌装机-长沙一星制药机械有限公司 | 铝合金电阻-无源谐波滤波器-上海稳达电讯设备厂 | 万博士范文网-您身边的范文参考网站Vanbs.com| 佛山市钱丰金属不锈钢蜂窝板定制厂家|不锈钢装饰线条|不锈钢屏风| 电梯装饰板|不锈钢蜂窝板不锈钢工艺板材厂家佛山市钱丰金属制品有限公司 | 南京展台搭建-南京展会设计-南京展览设计公司-南京展厅展示设计-南京汇雅展览工程有限公司 | 电池高低温试验箱-气态冲击箱-双层电池防爆箱|简户百科 | 机床主轴维修|刀塔维修|C轴维修-常州翔高精密机械有限公司 | 北京宣传片拍摄_产品宣传片拍摄_宣传片制作公司-现像传媒 | 爱德华真空泵油/罗茨泵维修,爱发科-比其尔产品供应东莞/杭州/上海等全国各地 | LINK FASHION 童装·青少年装展 河南卓美创业科技有限公司-河南卓美防雷公司-防雷接地-防雷工程-重庆避雷针-避雷器-防雷检测-避雷带-避雷针-避雷塔、机房防雷、古建筑防雷等-山西防雷公司 | 砖机托板价格|免烧砖托板|空心砖托板厂家_山东宏升砖机托板厂 | 涡街流量计_LUGB智能管道式高温防爆蒸汽温压补偿计量表-江苏凯铭仪表有限公司 |