java內(nèi)部類(lèi)有什么用购公?
搬運(yùn)一下oracle文檔:
https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
總結(jié)起來(lái)就是三點(diǎn):
1. 有些類(lèi)只對(duì)另外一個(gè)類(lèi)有用, 這樣可以組合在一起,讓整個(gè)包更精簡(jiǎn)陌知。比如Builder常常作為靜態(tài)內(nèi)部類(lèi)。
2. 增加封裝性掖肋。 比如有兩個(gè)類(lèi)A和B仆葡,B想要access A的成員。 如果將B作為A的內(nèi)部類(lèi)志笼,A的成員可以保持private沿盅,并且B本身也被封裝起來(lái)了。
3. 增加可讀性和維護(hù)性纫溃。讓代碼離它被用到的地方更近了腰涧。
內(nèi)部類(lèi)(inner class)
- 擁有外部類(lèi)的引用,這樣內(nèi)部類(lèi)可以訪(fǎng)問(wèn)創(chuàng)建它的外部類(lèi)的內(nèi)容紊浩,甚至包括私有變量南窗。
- 一旦編譯成功,就會(huì)成為完全不同的兩類(lèi)郎楼。
對(duì)于一個(gè)名為outer的外部類(lèi)和inner的內(nèi)部類(lèi)万伤,編譯完之后出現(xiàn)outer.class和outer$inner.class兩類(lèi)。 - 如果在外部類(lèi)外部訪(fǎng)問(wèn)內(nèi)部類(lèi),用out.inner
在外部類(lèi)外部要生成一個(gè)內(nèi)部類(lèi)對(duì)象:Outer.Inner in = Outer.new.Inner() - 外部類(lèi)可以訪(fǎng)問(wèn)內(nèi)部類(lèi)的private成員呜袁,神奇不神奇敌买。
編譯器實(shí)現(xiàn)的時(shí)候是這樣的:Outer類(lèi)和Inner類(lèi)不再是嵌套結(jié)構(gòu),而是變?yōu)橐粋€(gè)包中的兩個(gè)類(lèi)阶界,然后虹钮,對(duì)于private變量的訪(fǎng)問(wèn)聋庵,編譯器會(huì)生成一個(gè)accessor函數(shù)....... - 非靜態(tài)內(nèi)部類(lèi)不能有靜態(tài)數(shù)據(jù)、靜態(tài)方法芙粱、靜態(tài)內(nèi)部類(lèi)祭玉。
為啥呢?因?yàn)榇号希庆o態(tài)內(nèi)部類(lèi)的訪(fǎng)問(wèn)必須通過(guò)外部類(lèi)的實(shí)例脱货,所以要訪(fǎng)問(wèn)非靜態(tài)內(nèi)部類(lèi)的靜態(tài)方法,必須先實(shí)例化內(nèi)部類(lèi)和外部類(lèi)律姨,這樣就和靜態(tài)成員的設(shè)計(jì)是違背的振峻。
靜態(tài)內(nèi)部類(lèi)(靜態(tài)嵌套類(lèi))(nested class)
- 實(shí)際上是一種外部類(lèi),因?yàn)榕c外部類(lèi)的實(shí)例無(wú)關(guān)
- 定義在類(lèi)中择份,方法外
- 只能訪(fǎng)問(wèn)外部類(lèi)的靜態(tài)成員(可以訪(fǎng)問(wèn)私有的靜態(tài)成員)
- new的時(shí)候不需要外部類(lèi)成員:Outer.Inner in = new Outer.Inner();
局部?jī)?nèi)部類(lèi)
在一個(gè)方法甚至一個(gè)代碼塊之內(nèi)扣孟。
可以被final或abstract修飾
不能含有靜態(tài)成員
局部?jī)?nèi)部類(lèi)訪(fǎng)問(wèn)外部類(lèi)方法的局部變量要求其必須為final。
局部變量是隨著方法的調(diào)用而調(diào)用荣赶,隨著調(diào)用完畢而消失凤价。而堆內(nèi)存的對(duì)象內(nèi)容并不會(huì)立即消失。
或者簡(jiǎn)單的來(lái)說(shuō)是作用域的問(wèn)題拔创。就好像方法外面做的事情并不能改變方法內(nèi)才定義的變量料仗,因?yàn)槟悴⒉恢婪椒ɡ锩孢@個(gè)時(shí)候已經(jīng)存在了這個(gè)局部變量了沒(méi)有。在這個(gè)內(nèi)部類(lèi)中方法里面的本地變量是失效的伏蚊,也就是不在作用域內(nèi),所以是不能夠訪(fǎng)問(wèn)的格粪。但是為什么這里用final卻又可以訪(fǎng)問(wèn)呢躏吊? 因?yàn)镴ava采用了一種copy local variable的方式來(lái)實(shí)現(xiàn),也就是說(shuō)把定義為final的局部變量拷貝過(guò)來(lái)用帐萎,而引用的也可以拿過(guò)來(lái)用比伏,只是不能重新賦值。從而造成了可以access local variable的假象疆导,而這個(gè)時(shí)候由于不能重新賦值赁项,所以一般不會(huì)造成不可預(yù)料的事情發(fā)生。
則java編譯器則會(huì)在內(nèi)部類(lèi)NewAge內(nèi)生成一個(gè)外部變量的拷貝澈段,而且可以既可以保證內(nèi)部類(lèi)可以引用外部屬性悠菜,又能保證值的唯一性
也就是拷貝了一個(gè)變量的副本,提供給局部?jī)?nèi)部類(lèi),這個(gè)副本的生命周期和局部?jī)?nèi)部類(lèi)一樣長(zhǎng)败富,并且這個(gè)副本不可以修改悔醋,保證了數(shù)據(jù)的同步
注意:在Java8 中,被局部?jī)?nèi)部類(lèi)引用的局部變量兽叮,默認(rèn)添加final芬骄,所以不需要添加final關(guān)鍵詞
匿名內(nèi)部類(lèi)
- 匿名類(lèi)(Anonymouse Class)是一種沒(méi)有類(lèi)名的內(nèi)部類(lèi)猾愿,多用在事件處理的程序中。有時(shí)用戶(hù)需要定義一個(gè)類(lèi)账阻,且只想在程序中定義該類(lèi)的一個(gè)對(duì)象蒂秘,并把它作為參數(shù)傳遞給一個(gè)方法。只要該類(lèi)是一個(gè)現(xiàn)有類(lèi)的派生或?qū)崿F(xiàn)一個(gè)接口淘太,就可以使用匿名類(lèi)姻僧。匿名類(lèi)定義短而簡(jiǎn)單且使用方便,但不易過(guò)多使用琴儿,它會(huì)引起程序代碼的復(fù)雜化而不易理解
- 沒(méi)有名字段化,所以不能定義構(gòu)造方法。