日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

内部类详解————匿名内部类

發(fā)布時(shí)間:2025/3/12 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内部类详解————匿名内部类 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

內(nèi)部類(lèi)三連擊:

《內(nèi)部類(lèi)詳解————匿名內(nèi)部類(lèi)》

《內(nèi)部類(lèi)詳解————局部?jī)?nèi)部類(lèi)》

《內(nèi)部類(lèi)詳解————靜態(tài)嵌套類(lèi)》

應(yīng)用場(chǎng)景

由于匿名內(nèi)部類(lèi)不利于代碼的重用,因此,一般在確定此內(nèi)部類(lèi)只會(huì)使用一次時(shí),才會(huì)使用匿名內(nèi)部類(lèi)。

形式

public class OutterClass {public Runnable task() {return new Runnable() {@Overridepublic void run() {System.out.println("匿名內(nèi)部類(lèi)...");}};} }

這種實(shí)現(xiàn)方式是不是很眼熟呢?

// 初始化線程實(shí)例Thread thread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("匿名內(nèi)部類(lèi)...");}});

我們?yōu)榫€程創(chuàng)建一個(gè)Runnable子類(lèi)實(shí)例的方式,就是一種匿名內(nèi)部類(lèi)的寫(xiě)法。我們通過(guò)這種沒(méi)有名字的類(lèi),實(shí)現(xiàn)了將實(shí)現(xiàn)類(lèi)(下稱(chēng)子類(lèi))實(shí)例創(chuàng)建與子類(lèi)定義結(jié)合在一起的優(yōu)雅格式,這也就是所謂的“使用類(lèi)的定義直接創(chuàng)建實(shí)例”。

上面的代碼是實(shí)現(xiàn)了Runnable接口,并重寫(xiě)了其中的run()方法,當(dāng)然我們可以自己定義一個(gè)類(lèi)(非接口)然后通過(guò)這種匿名內(nèi)部類(lèi)的方式來(lái)隱式的繼承,并重寫(xiě)基類(lèi)中的方法。

不論是繼承父類(lèi),還是實(shí)現(xiàn)接口,實(shí)際上拿到的是父類(lèi)接口的引用。這個(gè)父類(lèi)引用實(shí)際指向的是一個(gè)由匿名內(nèi)部類(lèi)定義的類(lèi)的實(shí)例。因此,這個(gè)被繼承的父類(lèi)(或接口)必須是事先存在的。否則,編譯器會(huì)提示你創(chuàng)建這個(gè)類(lèi)。

使用規(guī)則

經(jīng)過(guò)查閱資料和實(shí)操得出的匿名內(nèi)部類(lèi)的幾條規(guī)則:

規(guī)則一:匿名內(nèi)部類(lèi)中的方法都是通過(guò)父類(lèi)引用訪問(wèn)的,所以,如果定義了一個(gè)在父類(lèi)中沒(méi)有的方法,那么這個(gè)方法是不能被這個(gè)父類(lèi)引用調(diào)用到的。(可以?xún)H僅作為匿名內(nèi)部類(lèi)中方法之間的代碼共享)。

規(guī)則二:匿名內(nèi)部類(lèi)既可以繼承父類(lèi),也可以實(shí)現(xiàn)接口,但是不能兩者兼?zhèn)洹6胰绻麑?shí)現(xiàn)接口也只能實(shí)現(xiàn)一個(gè)接口。

規(guī)則三:匿名內(nèi)部類(lèi)中不可能有構(gòu)造器。但可通過(guò)實(shí)例初始化塊 來(lái)達(dá)到構(gòu)造器的效果,但是也不能重載實(shí)例初始化方法(即僅有一個(gè)這樣的“構(gòu)造器”)。(關(guān)于實(shí)例初始化:《Java靜態(tài)初始化,實(shí)例初始化以及構(gòu)造方法》)

規(guī)則四:在匿名內(nèi)部類(lèi)中如果希望使用一個(gè)其外部定義的對(duì)象,那么編譯器會(huì)要求其參數(shù)引用是final的。

關(guān)于第四條規(guī)則,這里牽涉了一個(gè)重要的且比較復(fù)雜的問(wèn)題。

使用案例:

/** 定義接口*/ public interface MyInterface {void doSomething(); } public class TryUsingAnonymousClass {// 外部類(lèi)成員方法public MyInterface useMyInterface() {final int number = 201855;// jdk1.8后可以省略finalfinal Object obj = new Object();// jdk1.8后可以省略finalMyInterface myInterface = new MyInterface() {// 匿名內(nèi)部類(lèi)@Overridepublic void doSomething() {System.out.println("匿名內(nèi)部類(lèi)中使用基本數(shù)據(jù)類(lèi)型:" + number);System.out.println("匿名內(nèi)部類(lèi)中使用引用數(shù)據(jù)類(lèi)型:" + obj);}};return myInterface;}public static void main(String[] args) {TryUsingAnonymousClass tc = new TryUsingAnonymousClass();MyInterface inter = tc.useMyInterface();inter.doSomething();} }

輸出:

匿名內(nèi)部類(lèi)中使用基本數(shù)據(jù)類(lèi)型:201855 匿名內(nèi)部類(lèi)中使用引用數(shù)據(jù)類(lèi)型:java.lang.Object@15db9742

我們通過(guò)匿名內(nèi)部類(lèi)的方式實(shí)現(xiàn)了接口MyInterface,并使用了外部類(lèi)的成員方法useMyInterface() 中定義的兩個(gè)局部變量:

int number = 201855; Object obj = new Object();

(在jdk1.8之后,新增了effectively final功能,開(kāi)發(fā)者可以不必顯式地使用final關(guān)鍵字來(lái)修飾局部?jī)?nèi)部類(lèi)或匿名內(nèi)部類(lèi)中用到的局部變量,由系統(tǒng)默認(rèn)添加。)

因此我們?cè)谀涿麅?nèi)部類(lèi)中用到的局部變量必須為常量(對(duì)于基本類(lèi)型,其值恒定不變;對(duì)于引用類(lèi)型,其引用,即指向的地址恒定不變)。

如果強(qiáng)行改值,則會(huì)報(bào)錯(cuò)(這是在1.8程序上未使用final定義number時(shí)的嘗試,系統(tǒng)果然默認(rèn)此值為final的):

不得不引出的局部變量與匿名內(nèi)部類(lèi)實(shí)例生命周期問(wèn)題

我們知道成員方法中的局部變量是在運(yùn)行期進(jìn)行定義和初始化的,而局部?jī)?nèi)部類(lèi)(包括匿名內(nèi)部類(lèi))雖然是在方法中定義的,但是它卻依然會(huì)在編譯期實(shí)現(xiàn)從java文件到class文件的轉(zhuǎn)化,即編譯成class文件。

編譯期在前,運(yùn)行期在后。而我們卻要在編譯期使用運(yùn)行期定義的變量!

怎么辦?我們腦海中浮現(xiàn)了兩個(gè)在編譯期便能取得常量的相關(guān)關(guān)鍵字:static final ?但顯然,static無(wú)法定義局部變量。

那final能為我們的程序帶來(lái)什么?

翻閱《Java編程思想》中對(duì)final關(guān)鍵字的剖析(第四版,140頁(yè)):

一個(gè)永不改變的編譯時(shí)常量。

《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐》中(第二版,168頁(yè))對(duì)于Class文件常量池也做出了相關(guān)解釋:

常量池(博主注:此常量池為class文件常量池,非運(yùn)行時(shí)常量池,兩者最大的區(qū)別是后者具有動(dòng)態(tài)性) 中主要存放兩大類(lèi)常量:字面量和符號(hào)引用。字面量比較接近于Java語(yǔ)言層的常量概念,如文本字符串、聲明為final的常量值等。

匿名內(nèi)部類(lèi)被編譯成了class文件,它將final定義的局部變量編譯進(jìn)了class文件的常量池中,因此,我們會(huì)看上面的代碼:

public static void main(String[] args) {TryUsingAnonymousClass tc = new TryUsingAnonymousClass();MyInterface inter = tc.useMyInterface();inter.doSomething();}

int型局部變量number和Object類(lèi)型obj在方法useMyInterface()執(zhí)行完畢之后即結(jié)束了生命周期,但是在下面通過(guò)調(diào)用inter對(duì)象的doSomething()方法依然可以有效的輸出這兩個(gè)值,說(shuō)明這兩個(gè)常量并沒(méi)有受到外部類(lèi)方法執(zhí)行完畢而導(dǎo)致局部變量生命周期結(jié)束的問(wèn)題,實(shí)際上number和obj已經(jīng)存在于匿名內(nèi)部類(lèi)對(duì)應(yīng)的class文件中的常量池中。

雖然final修飾的常量解決了在編譯期拿到運(yùn)行期的變量的問(wèn)題,但是final帶來(lái)的副作用是,這個(gè)值無(wú)法改變。

對(duì)于需要改變局部變量值的情況,我們可以通過(guò)在匿名內(nèi)部類(lèi)中使用賦值的方式(學(xué)名:引用拷貝 =.0)來(lái)“接管”局部變量的值,然后我們就可以隨意更改這個(gè)值了。

綜上,就是最近對(duì)匿名內(nèi)部類(lèi)的研究和討論。結(jié)合了final關(guān)鍵字的用法和class文件常量池來(lái)多角度討論匿名內(nèi)部類(lèi)的final常量問(wèn)題。后期如果有什么新的理解還會(huì)繼續(xù)更新。文中的錯(cuò)別字和排版不適感博主已經(jīng)進(jìn)行了糾錯(cuò)和修改,如果各位在閱讀時(shí)發(fā)現(xiàn)了任何錯(cuò)誤,都請(qǐng)?jiān)谖哪┝粞浴?/p>

?

總結(jié)

以上是生活随笔為你收集整理的内部类详解————匿名内部类的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。