深入解析Java中的內(nèi)部類(lèi)
概述
最近學(xué)習(xí)python,發(fā)現(xiàn)python是支持多繼承的,這讓我想起Java是通過(guò)內(nèi)部類(lèi)實(shí)現(xiàn)的這套機(jī)制。這篇文章不是講如何通過(guò)內(nèi)部類(lèi)實(shí)現(xiàn)多繼承,而是總結(jié)一下內(nèi)部類(lèi)的類(lèi)型和使用方法。
Java內(nèi)部類(lèi)分為:
- 非靜態(tài)內(nèi)部類(lèi)
- 靜態(tài)內(nèi)部類(lèi)
- 局部?jī)?nèi)部類(lèi)
- 匿名內(nèi)部類(lèi)
內(nèi)部類(lèi)在Android源碼中被大量的使用,先介紹一下這四種內(nèi)部類(lèi)的共同點(diǎn):
- 內(nèi)部類(lèi)仍然是一個(gè)獨(dú)立的類(lèi),在編譯之后內(nèi)部類(lèi)會(huì)被編譯成獨(dú)立的.class文件,但是前面冠以外部類(lèi)的類(lèi)名和$符號(hào)。
- 內(nèi)部類(lèi)不能用普通的方式訪問(wèn)。內(nèi)部類(lèi)是外部類(lèi)的一個(gè)成員,因?yàn)閮?nèi)部類(lèi)可以自由的訪問(wèn)外部類(lèi)的成員,包括private成員。
- 內(nèi)部類(lèi)聲明為靜態(tài)的,就不能隨意的訪問(wèn)外部類(lèi)的成員變量了,此時(shí)內(nèi)部類(lèi)只能訪問(wèn)到外部類(lèi)的靜態(tài)成員變量。
接下來(lái),分別介紹一下這幾種內(nèi)部類(lèi)。
非靜態(tài)內(nèi)部類(lèi)
當(dāng)一個(gè)類(lèi)作為另一個(gè)類(lèi)的非靜態(tài)成員時(shí),則這個(gè)類(lèi)就是一個(gè)非靜態(tài)內(nèi)部類(lèi)。
創(chuàng)建非靜態(tài)內(nèi)部類(lèi)的示例代碼如下:
class OutClass { class InnerClass {} }
當(dāng)我們用javac去編譯的時(shí)候,發(fā)現(xiàn)生成了兩個(gè).class文件:OutClass.class和OutClass$InnerClass.class。如下圖所示:
從外部類(lèi)的非靜態(tài)方法中實(shí)例化內(nèi)部類(lèi)
在外部類(lèi)中訪問(wèn)內(nèi)部類(lèi)是很容易的,直接創(chuàng)建內(nèi)部類(lèi)對(duì)象,然后通過(guò)對(duì)象實(shí)例調(diào)用類(lèi)內(nèi)的方法即可。示例代碼如下:
public class OutClass { private static int a = 0; public void makeInner() { InnerClass inClass = new InnerClass(); inClass.seeOuter(); } public static void main(String[] args) { OutClass oClass = new OutClass(); oClass.makeInner(); } class InnerClass { public void seeOuter() { System.out.println(a); a++; } } }
0
從外部類(lèi)的靜態(tài)方法中實(shí)例化內(nèi)部類(lèi)
在外部類(lèi)中訪問(wèn)內(nèi)部類(lèi)是比較簡(jiǎn)單的,可以直接new出內(nèi)部類(lèi)對(duì)象,但是如果想在外部類(lèi)的外部使用內(nèi)部類(lèi),接不能直接new內(nèi)部類(lèi)名的方式了,而是需要如下方式:
OutClass.InnerClass innerClass = new OutClass().new InnerClass();
也就是說(shuō),在外部調(diào)用非靜態(tài)內(nèi)部類(lèi),需要先實(shí)例化外部類(lèi),然后通過(guò)外部類(lèi)對(duì)象再去實(shí)例化內(nèi)部類(lèi)。示例代碼如下:
public class OutClass { private static int a = 0; public void makeInner() { InnerClass inClass = new InnerClass(); inClass.seeOuter(); } public static void main(String[] args) { OutClass oClass = new OutClass(); oClass.makeInner(); OutClass.InnerClass innerClass = new OutClass().new InnerClass(); innerClass.seeOuter(); } class InnerClass { public void seeOuter() { System.out.println(a); a++; } } }
運(yùn)行結(jié)果:
0 1
內(nèi)部類(lèi)的this引用
普通的類(lèi)可以使用this引用當(dāng)前的對(duì)象,內(nèi)部類(lèi)也是如此。但是假若內(nèi)部類(lèi)想引用外部類(lèi)當(dāng)前的對(duì)象呢?可以使用如下方式:
外部類(lèi)名.this
示例代碼如下:
public class OutClass { private static int a = 0; public void makeInner() { InnerClass inClass = new InnerClass(); inClass.seeOuter(); } public static void main(String[] args) { OutClass oClass = new OutClass(); oClass.makeInner(); OutClass.InnerClass innerClass = new OutClass().new InnerClass(); innerClass.seeOuter(); } class InnerClass { public void seeOuter() { System.out.println(this); System.out.println(OutClass.this); } } }
靜態(tài)內(nèi)部類(lèi)
上面介紹了非靜態(tài)內(nèi)部類(lèi),接下來(lái)我們學(xué)習(xí)神馬是靜態(tài)內(nèi)部類(lèi)。
靜態(tài)內(nèi)部類(lèi)就是在外部類(lèi)中扮演一個(gè)靜態(tài)成員的角色,創(chuàng)建靜態(tài)內(nèi)部類(lèi)和創(chuàng)建非靜態(tài)內(nèi)部類(lèi)的形式很相似,只是class前面多了一個(gè)static修飾符。
注意,外部類(lèi)是不可能使用static修飾符進(jìn)行修飾的。
示例代碼如下:
class OutClass { static class InnerClass { } }
用javac命令編譯一下,可以看到一樣都是有兩個(gè).class文件,如下圖所示:
從外部類(lèi)的非靜態(tài)方法中實(shí)例化靜態(tài)內(nèi)部類(lèi)
從外部類(lèi)中訪問(wèn)靜態(tài)內(nèi)部類(lèi),和在外部類(lèi)中訪問(wèn)非靜態(tài)內(nèi)部類(lèi)是一樣的。但是,需要注意一點(diǎn),此時(shí)靜態(tài)內(nèi)部類(lèi)只能訪問(wèn)外部類(lèi)的靜態(tài)成員,無(wú)法訪問(wèn)非靜態(tài)成員了。
示例代碼如下:
public class OutClass { private static int a = 0; private int b = 1; public void makeInner() { InnerClass inClass = new InnerClass(); inClass.seeOuter(); } public static void main(String[] args) { OutClass oClass = new OutClass(); oClass.makeInner(); } static class InnerClass { public void seeOuter() { System.out.println(this); System.out.println(a); // System.out.println(b); } } }
執(zhí)行結(jié)果如下:
OutClass$InnerClass@79a340 0
從外部類(lèi)靜態(tài)方法中實(shí)例化靜態(tài)內(nèi)部類(lèi)
注意:
因?yàn)殪o態(tài)內(nèi)部類(lèi)是外部類(lèi)的靜態(tài)成員,而靜態(tài)成員是跟類(lèi)綁定,而不是跟類(lèi)實(shí)例化的對(duì)象綁定。所以,在外部類(lèi)的靜態(tài)方法中實(shí)例化內(nèi)部類(lèi),是不需要先實(shí)例化外部類(lèi)的。
示例代碼如下:
public class OutClass { private static int a = 0; private int b = 1; public void makeInner() { InnerClass inClass = new InnerClass(); inClass.seeOuter(); } public static void main(String[] args) { OutClass oClass = new OutClass(); oClass.makeInner(); OutClass.InnerClass inClass = new OutClass.InnerClass(); inClass.seeOuter(); } static class InnerClass { public void seeOuter() { System.out.println(this); System.out.println(a); // System.out.println(b); } } }
匿名內(nèi)部類(lèi)
匿名內(nèi)部類(lèi)在Android應(yīng)用開(kāi)發(fā)中簡(jiǎn)直是泛濫,各種listener對(duì)象的實(shí)現(xiàn)很多都是通過(guò)匿名內(nèi)部類(lèi)。
匿名內(nèi)部類(lèi)從名字上就可以知道這是代表沒(méi)有類(lèi)名的內(nèi)部類(lèi),通常用來(lái)簡(jiǎn)化代碼。
相信寫(xiě)Java的同學(xué)都使用過(guò)線程,那Thread的時(shí)候我們可以傳一個(gè)Runnable對(duì)象,也可以傳一個(gè)匿名內(nèi)部類(lèi)。示例代碼如下:
public class OutClass { public void testAnonymousClass() { Thread t = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i ++) { System.out.println(i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }); t.start(); System.out.println("another thread is running..."); } public static void main(String[] args) { OutClass oClass = new OutClass(); oClass.testAnonymousClass(); } }
執(zhí)行結(jié)果如下:
another thread is running...
- 對(duì)Java的面對(duì)對(duì)象編程中對(duì)象和引用以及內(nèi)部類(lèi)的理解
- 整理java讀書(shū)筆記十五之java中的內(nèi)部類(lèi)
- 全面解讀Java編程中的內(nèi)部類(lèi)
- 講解Java中如何構(gòu)造內(nèi)部類(lèi)對(duì)象以及訪問(wèn)對(duì)象
- Java內(nèi)部類(lèi)的繼承(全)
- 深入解析Java中的Class Loader類(lèi)加載器
- java基礎(chǔ)學(xué)習(xí)筆記之類(lèi)加載器
- 解析Java虛擬機(jī)中類(lèi)的初始化及加載器的父委托機(jī)制
- 舉例講解Java的內(nèi)部類(lèi)與類(lèi)的加載器
相關(guān)文章
Java中為什么this可以調(diào)用當(dāng)前實(shí)例
本文主要介紹了為什么可以通過(guò)this關(guān)鍵字訪問(wèn)到當(dāng)前對(duì)象呢,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07Spring?Boot使用Hibernate-Validator校驗(yàn)參數(shù)時(shí)的長(zhǎng)度校驗(yàn)方法詳解
這篇文章主要給大家介紹了關(guān)于Spring?Boot使用Hibernate-Validator校驗(yàn)參數(shù)時(shí)的長(zhǎng)度校驗(yàn)方法的相關(guān)資料,在Spring Boot中可以使用Spring Boot Validation來(lái)對(duì)參數(shù)名稱(chēng)進(jìn)行校驗(yàn),需要的朋友可以參考下2023-08-08SpringBoot通過(guò)整合Dubbo解決@Reference注解問(wèn)題
這篇文章主要介紹了SpringBoot通過(guò)整合Dubbo解決@Reference注解問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03springboot相互依賴(lài) server相互引用方式
這篇文章主要介紹了springboot相互依賴(lài) server相互引用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02Java開(kāi)發(fā)druid數(shù)據(jù)連接池maven方式簡(jiǎn)易配置流程示例
本篇文章主要為大家介紹了java開(kāi)發(fā)中druid數(shù)據(jù)連接池maven方式的簡(jiǎn)易配置流程示例,文中附含詳細(xì)的代碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10