這篇文章主要為大家詳細(xì)介紹了Java內(nèi)部類的用法,文中示例代碼介紹的非常詳細(xì),零基礎(chǔ)也能參考此文章,感興趣的小伙伴們可以參考一下。
成都創(chuàng)新互聯(lián)公司專注于湛江企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè),購物商城網(wǎng)站建設(shè)。湛江網(wǎng)站建設(shè)公司,為湛江等地區(qū)提供建站服務(wù)。全流程按需網(wǎng)站設(shè)計(jì),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)內(nèi)部類(inner class)是定義在另一個類內(nèi)部的類。之所以定義在內(nèi)部是因?yàn)閮?nèi)部類有一些普通類沒有的“特權(quán)”,可以方便實(shí)現(xiàn)一些需求。
內(nèi)部類
先來看一個簡單的例子:
public class Apple { private int size = 16; private class Book { public void print() { System.out.println(size); } } }
Book類就是定義在Apple類中的一個內(nèi)部類,Book類引用了Apple類的私有域size卻沒有報錯,這就是上文提到的特權(quán)了,內(nèi)部類可以引用外圍類的所有域和方法包括私有的。那么為什么內(nèi)部類可以做到這樣神奇的事情呢?原來是編譯器在背后偷偷干的好事!
把上文的例子編譯后可以看到編譯器會額外生成一個Apple$Book.class文件:
class Apple$Book { private Apple$Book(Apple var1) { this.this$0 = var1; } public void print() { System.out.println(Apple.access$000(this.this$0)); } }
可以看到這個類的名稱是用外圍類名稱加內(nèi)部類名稱用$符號分割,而且編譯器在內(nèi)部類的構(gòu)造函數(shù)里自動添加了一個外圍類的參數(shù),這樣內(nèi)部類就能引用到外圍類的域和參數(shù)了。
不過這樣還有一個問題,我們完全可以按普通的方式自己寫一個構(gòu)建方式來接收Apple類而不用內(nèi)部類的方式,不過這樣的類卻無法引用Apple類的私有域和私有方法。
眼尖的同學(xué)可能已經(jīng)發(fā)現(xiàn)奧秘了,Apple.access$000(this.this$0)這一條語句就是關(guān)鍵了。內(nèi)部類在引用外圍類的私有域和方法時編譯器會在外圍類內(nèi)部生成一個靜態(tài)方法access$XXX,這個方法會返回外圍類的私有域或調(diào)用私有方法,方法的第一個參數(shù)是外圍類的引用。
不過這樣就有了安全風(fēng)險,任何人都可以通過調(diào)用Apple.access$000方法很容易地讀取到私有域size。當(dāng)然,access$000不是Java的合法方法名。但熟悉類文件結(jié)構(gòu)的黑客可以使用十六進(jìn)制編輯器輕松地創(chuàng)建一個用虛擬機(jī)指令調(diào)用那個方法的類文件。由于隱秘地訪問方法需要擁有包可見性,所以攻擊代碼需要與被攻擊類放在同一個包中。
特殊的語法
內(nèi)部類有一些特殊的語法,比如獲取傳入的外圍類引用的語法是OuterClass.this,外圍類的類名加上this關(guān)鍵字。還有明確的使用內(nèi)部類的構(gòu)建函數(shù)outerObject.new InnerClass {construction parameters)。在內(nèi)部類中聲明的靜態(tài)域必須是不可變的,即必須用final修飾符修飾,且不能有靜態(tài)方法。例子:
public class Apple { private int size = 16; private class Book { public void print() { System.out.println(Apple.this.size); } } public static void main(String[] args) { Apple apple = new Apple(); Apple.Book book = apple.new Book(); } }
局部內(nèi)部類
內(nèi)部類也可以在一個方法內(nèi)聲明,這樣定義的內(nèi)部類就是局部內(nèi)部類。局部內(nèi)部類和內(nèi)部類的區(qū)別在于局部內(nèi)部類的作用域局限于定義它的方法塊內(nèi),除了這個方法內(nèi)部局部內(nèi)部類都是不可見的。
public class Apple { private int size = 16; private void print() { class Book { public void print() { System.out.println(size); } } Book book = new Book(); book.print(); } }
匿名內(nèi)部類
顧名思義,匿名內(nèi)部類是一種沒有類名的類。因?yàn)橛袝r候我們只需要有一個一次性使用的類的對象,匿名內(nèi)部類可以方便我們實(shí)現(xiàn)。通常的語法格式為:
SuperType superType = new SuperType(construction parameters) { inner class methods and data }
如果SuperType是一個接口,那么就需要在大括號里實(shí)現(xiàn)接口定義的抽象方法。如果SuperType是一個類,可以在大括號里擴(kuò)展這個類。因?yàn)槟涿麅?nèi)部類沒有類名,所以是不能定義構(gòu)建函數(shù)的。在Java8以后,使用lambda表達(dá)式會比匿名內(nèi)部類更加方便。
雙括號初始化
利用匿名內(nèi)部類的特殊語法的特殊初始化技巧,比如初始化一個數(shù)組:
ListarrayList = new ArrayList () {{ add("test"); add("test2"); }};
不過就這個例子來說這樣更好:List
靜態(tài)內(nèi)部類
上文說到內(nèi)部類都會有一個外圍類的引用,不過有時我們只是想把類放在另一個類內(nèi)部并不需要引用它,這時就可以用到靜態(tài)內(nèi)部類。例子:
public class Apple { private int size; private int price; public Apple(int size, int price) { this.size = size; this.price = price; } public static void main(String[] args) { Apple apple = AppleBuilder.builder().setPrice(20).setSize(16).build(); } static class AppleBuilder { private int size; private int price; static AppleBuilder builder() { return new AppleBuilder(); } Apple build() { return new Apple(size, price); } AppleBuilder setSize(int size) { this.size = size; return this; } AppleBuilder setPrice(int price) { this.price = price; return this; } } }
以上就是Java內(nèi)部類的詳細(xì)內(nèi)容,代碼示例簡單明了,如果在日常工作遇到此問題。通過這篇文章,希望你能有所收獲,更多詳情敬請關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司行業(yè)資訊頻道!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。