深入解析Java中的內(nèi)部類
概述
最近學(xué)習(xí)python,發(fā)現(xiàn)python是支持多繼承的,這讓我想起Java是通過(guò)內(nèi)部類實(shí)現(xiàn)的這套機(jī)制。這篇文章不是講如何通過(guò)內(nèi)部類實(shí)現(xiàn)多繼承,而是總結(jié)一下內(nèi)部類的類型和使用方法。
Java內(nèi)部類分為:
- 非靜態(tài)內(nèi)部類
- 靜態(tài)內(nèi)部類
- 局部?jī)?nèi)部類
- 匿名內(nèi)部類
內(nèi)部類在Android源碼中被大量的使用,先介紹一下這四種內(nèi)部類的共同點(diǎn):
- 內(nèi)部類仍然是一個(gè)獨(dú)立的類,在編譯之后內(nèi)部類會(huì)被編譯成獨(dú)立的.class文件,但是前面冠以外部類的類名和$符號(hào)。
- 內(nèi)部類不能用普通的方式訪問(wèn)。內(nèi)部類是外部類的一個(gè)成員,因?yàn)閮?nèi)部類可以自由的訪問(wèn)外部類的成員,包括private成員。
- 內(nèi)部類聲明為靜態(tài)的,就不能隨意的訪問(wèn)外部類的成員變量了,此時(shí)內(nèi)部類只能訪問(wèn)到外部類的靜態(tài)成員變量。
接下來(lái),分別介紹一下這幾種內(nèi)部類。
非靜態(tài)內(nèi)部類
當(dāng)一個(gè)類作為另一個(gè)類的非靜態(tài)成員時(shí),則這個(gè)類就是一個(gè)非靜態(tài)內(nèi)部類。
創(chuàng)建非靜態(tài)內(nèi)部類的示例代碼如下:
class OutClass {
class InnerClass {}
}
當(dāng)我們用javac去編譯的時(shí)候,發(fā)現(xiàn)生成了兩個(gè).class文件:OutClass.class和OutClass$InnerClass.class。如下圖所示:

從外部類的非靜態(tài)方法中實(shí)例化內(nèi)部類
在外部類中訪問(wèn)內(nèi)部類是很容易的,直接創(chuàng)建內(nèi)部類對(duì)象,然后通過(guò)對(duì)象實(shí)例調(diào)用類內(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
從外部類的靜態(tài)方法中實(shí)例化內(nèi)部類
在外部類中訪問(wèn)內(nèi)部類是比較簡(jiǎn)單的,可以直接new出內(nèi)部類對(duì)象,但是如果想在外部類的外部使用內(nèi)部類,接不能直接new內(nèi)部類名的方式了,而是需要如下方式:
OutClass.InnerClass innerClass = new OutClass().new InnerClass();
也就是說(shuō),在外部調(diào)用非靜態(tài)內(nèi)部類,需要先實(shí)例化外部類,然后通過(guò)外部類對(duì)象再去實(shí)例化內(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();
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)部類的this引用
普通的類可以使用this引用當(dāng)前的對(duì)象,內(nèi)部類也是如此。但是假若內(nèi)部類想引用外部類當(dāng)前的對(duì)象呢?可以使用如下方式:
外部類名.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)部類
上面介紹了非靜態(tài)內(nèi)部類,接下來(lái)我們學(xué)習(xí)神馬是靜態(tài)內(nèi)部類。
靜態(tài)內(nèi)部類就是在外部類中扮演一個(gè)靜態(tài)成員的角色,創(chuàng)建靜態(tài)內(nèi)部類和創(chuàng)建非靜態(tài)內(nèi)部類的形式很相似,只是class前面多了一個(gè)static修飾符。
注意,外部類是不可能使用static修飾符進(jìn)行修飾的。
示例代碼如下:
class OutClass {
static class InnerClass {
}
}
用javac命令編譯一下,可以看到一樣都是有兩個(gè).class文件,如下圖所示:

從外部類的非靜態(tài)方法中實(shí)例化靜態(tài)內(nèi)部類
從外部類中訪問(wèn)靜態(tài)內(nèi)部類,和在外部類中訪問(wèn)非靜態(tài)內(nèi)部類是一樣的。但是,需要注意一點(diǎn),此時(shí)靜態(tài)內(nèi)部類只能訪問(wèn)外部類的靜態(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
從外部類靜態(tài)方法中實(shí)例化靜態(tài)內(nèi)部類
注意:
因?yàn)殪o態(tài)內(nèi)部類是外部類的靜態(tài)成員,而靜態(tài)成員是跟類綁定,而不是跟類實(shí)例化的對(duì)象綁定。所以,在外部類的靜態(tài)方法中實(shí)例化內(nèi)部類,是不需要先實(shí)例化外部類的。
示例代碼如下:
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)部類
匿名內(nèi)部類在Android應(yīng)用開發(fā)中簡(jiǎn)直是泛濫,各種listener對(duì)象的實(shí)現(xiàn)很多都是通過(guò)匿名內(nèi)部類。
匿名內(nèi)部類從名字上就可以知道這是代表沒(méi)有類名的內(nèi)部類,通常用來(lái)簡(jiǎn)化代碼。
相信寫Java的同學(xué)都使用過(guò)線程,那Thread的時(shí)候我們可以傳一個(gè)Runnable對(duì)象,也可以傳一個(gè)匿名內(nè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...
相關(guān)文章
Java按照List內(nèi)存儲(chǔ)的對(duì)象的某個(gè)字段進(jìn)行排序的實(shí)例
下面小編就為大家?guī)?lái)一篇Java按照List內(nèi)存儲(chǔ)的對(duì)象的某個(gè)字段進(jìn)行排序的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
Spring mvc防止數(shù)據(jù)重復(fù)提交的方法
這篇文章主要為大家詳細(xì)介紹了Spring mvc防止數(shù)據(jù)重復(fù)提交的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
SpringBoot自動(dòng)配置的8個(gè)技巧分享
在 SpringBoot 2.x中,一個(gè)很核心的功能是自動(dòng)配置機(jī)制,這篇文章主要為大家詳細(xì)介紹了Spring Boot 2.x 實(shí)現(xiàn)自動(dòng)配置的8個(gè)技巧,希望對(duì)大家有所幫助2025-01-01
Java程序去調(diào)用并執(zhí)行shell腳本及問(wèn)題總結(jié)(推薦)
這篇文章主要介紹了Java程序去調(diào)用并執(zhí)行shell腳本及問(wèn)題總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
在IDEA中創(chuàng)建父工程和子模塊module的方法步驟
這篇文章主要介紹了在IDEA中創(chuàng)建父工程和子模塊module的方法步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
springboot項(xiàng)目整合druid數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)
這篇文章主要介紹了springboot項(xiàng)目整合druid數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
java協(xié)程框架quasar和kotlin中的協(xié)程對(duì)比分析
這篇文章主要為大家介紹了java協(xié)程框架quasar和kotlin兩個(gè)協(xié)程對(duì)比分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多基本2022-02-02
springboot~ObjectMapper~dto到entity的自動(dòng)賦值
這篇文章主要介紹了springboot~ObjectMapper~dto到entity的自動(dòng)賦值,本文分三種情況給大家介紹,需要的朋友可以參考下2018-08-08
Mybatis控制臺(tái)打印SQL執(zhí)行信息的方法詳解
SQL性能監(jiān)控是一個(gè)程序必要的功能,通常我們可以使用數(shù)據(jù)庫(kù)自帶的客戶端工具進(jìn)行SQL性能分析,本章節(jié)只實(shí)現(xiàn)Mybatis執(zhí)行時(shí)對(duì)執(zhí)行SQL進(jìn)行攔截,控制臺(tái)打印執(zhí)行SQL包括參數(shù)、執(zhí)行方法以及執(zhí)行時(shí)間,需要的朋友可以參考下2024-11-11

