此文已經(jīng)同步至個(gè)人站點(diǎn)博客吝镣,點(diǎn)擊下方鏈接可以體驗(yàn)更加閱讀模式:
《java題庫》
一.面向?qū)ο蟮幕靖拍?/h4>
1.解釋下多態(tài)性(polymorphism),封裝性(encapsulation)次舌,內(nèi)聚(cohesion)以及耦合(coupling)
抽象:抽象是將一類對(duì)象的共同特征總結(jié)出來構(gòu)造類的過程,包括數(shù)據(jù)抽象和行為抽象兩方面肆氓。抽象只關(guān)注對(duì)象有哪些屬性和行為去枷,并不關(guān)注這些行為的細(xì)節(jié)是什么。
封裝:通常認(rèn)為封裝是把數(shù)據(jù)和操作數(shù)據(jù)的方法綁定起來邪码,對(duì)數(shù)據(jù)的訪問只能通過已定義的接口裕菠。面向?qū)ο蟮谋举|(zhì)就是將現(xiàn)實(shí)世界描繪成一系列完全自治、封閉的對(duì)象闭专。我們?cè)陬愔芯帉懙姆椒ň褪菍?duì)實(shí)現(xiàn)細(xì)節(jié)的一種封裝奴潘;我們編寫一個(gè)類就是對(duì)數(shù)據(jù)和數(shù)據(jù)操作的封裝∮岸ぃ可以說画髓,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口(可以想想普通洗衣機(jī)和全自動(dòng)洗衣機(jī)的差別斧拍,明顯全自動(dòng)洗衣機(jī)封裝更好因此操作起來更簡單雀扶;我們現(xiàn)在使用的智能手機(jī)也是封裝得足夠好的,因?yàn)閹讉€(gè)按鍵就搞定了所有的事情)肆汹。
好處有三:1愚墓、隱藏了類的實(shí)現(xiàn);2昂勉、操作簡單浪册;3、提高對(duì)象數(shù)據(jù)的安全性
內(nèi)聚:進(jìn)行架構(gòu)設(shè)計(jì)時(shí)的內(nèi)聚高低是指岗照,設(shè)計(jì)某個(gè)模塊或者關(guān)注點(diǎn)時(shí)村象,模塊或關(guān)注點(diǎn)內(nèi)部的一系列相關(guān)功能的相關(guān)程度的高低笆环。高內(nèi)聚提供了更好的可維護(hù)性和可復(fù)用性。而低內(nèi)聚的模塊則表名模塊直接的依賴程度高厚者,那么一旦修改了該模塊依賴的對(duì)象則無法使用該模塊躁劣,必須也進(jìn)行相應(yīng)的修改才可以繼續(xù)使用。
耦合:簡單地說库菲,軟件工程中對(duì)象之間的耦合度就是對(duì)象之間的依賴性账忘。指導(dǎo)使用和維護(hù)對(duì)象的主要問題是對(duì)象之間的多重依賴性。對(duì)象之間的耦合越高熙宇,維護(hù)成本越高鳖擒。因此對(duì)象的設(shè)計(jì)應(yīng)使類和構(gòu)件之間的耦合最小。耦合性是程序結(jié)構(gòu)中各個(gè)模塊之間相互關(guān)聯(lián)的度量烫止。它取決于各個(gè)模塊之間的接口的復(fù)雜程度蒋荚、調(diào)用模塊的方式以及哪些信息通過接口。
耦合可以分為以下幾種馆蠕,它們之間的耦合度由高到低排列如下:
- 內(nèi)容耦合期升。當(dāng)一個(gè)模塊直接修改或操作另一個(gè)模塊的數(shù)據(jù)時(shí),或一個(gè)模塊不通過正常入口而轉(zhuǎn)入另一個(gè)模塊時(shí)荆几,這樣的耦合被稱為內(nèi)容耦合吓妆。內(nèi)容耦合是最高程度的耦合,應(yīng)該避免使用之吨铸。
- 公共耦合。兩個(gè)或兩個(gè)以上的模塊共同引用一個(gè)全局?jǐn)?shù)據(jù)項(xiàng)祖秒,這種耦合被稱為公共耦合诞吱。在具有大量公共耦合的結(jié)構(gòu)中,確定究竟是哪個(gè)模塊給全局變量賦了一個(gè)特定的值是十分困難的竭缝。
-
外部耦合 房维。一組模塊都訪問同一全局簡單變量而不是同一全局?jǐn)?shù)據(jù)結(jié)構(gòu),而且不是通過參數(shù)表傳遞該全局變量的信息抬纸,則稱之為外部耦合咙俩。
控制耦合 。一個(gè)模塊通過接口向另一個(gè)模塊傳遞一個(gè)控制信號(hào)湿故,接受信號(hào)的模塊根據(jù)信號(hào)值而進(jìn)行適當(dāng)?shù)膭?dòng)作阿趁,這種耦合被稱為控制耦合。
標(biāo)記耦合 。若一個(gè)模塊A通過接口向兩個(gè)模塊B和C傳遞一個(gè)公共參數(shù)呜呐,那么稱模塊B和C之間存在一個(gè)標(biāo)記耦合悍募。 - 數(shù)據(jù)耦合。模塊之間通過參數(shù)來傳遞數(shù)據(jù),那么被稱為數(shù)據(jù)耦合。數(shù)據(jù)耦合是最低的一種耦合形式,系統(tǒng)中一般都存在這種類型的耦合,因?yàn)闉榱送瓿梢恍┯幸饬x的功能,往往需要將某些模塊的輸出數(shù)據(jù)作為另一些模塊的輸入數(shù)據(jù)。
-
非直接耦合 曲横。兩個(gè)模塊之間沒有直接關(guān)系,它們之間的聯(lián)系完全是通過主模塊的控制和調(diào)用來實(shí)現(xiàn)的。
高內(nèi)聚&低耦合
2.多態(tài)的用途和實(shí)現(xiàn)原理(★★★)
1题禀、編譯時(shí)多態(tài)(又稱靜態(tài)多態(tài))
2秀仲、運(yùn)行時(shí)多態(tài)(又稱動(dòng)態(tài)多態(tài))
重載(overload)就是編譯時(shí)多態(tài)的一個(gè)例子沛励,編譯時(shí)多態(tài)在編譯時(shí)就已經(jīng)確定,運(yùn)行時(shí)運(yùn)行的時(shí)候調(diào)用的是確定的方法。
我們通常所說的多態(tài)指的都是運(yùn)行時(shí)多態(tài)它呀,也就是編譯時(shí)不確定究竟調(diào)用哪個(gè)具體方法,一直延遲到運(yùn)行時(shí)才能確定。這也是為什么有時(shí)候多態(tài)方法又被稱為延遲方法的原因拷淘。
- 多態(tài)通常有兩種實(shí)現(xiàn)方法:
1、子類繼承父類(extends)
2启涯、子類實(shí)現(xiàn)接口(implements) -
多態(tài)最大的用途
個(gè)人認(rèn)為在于對(duì)設(shè)計(jì)和架構(gòu)的復(fù)用,更進(jìn)一步來說挽铁,《設(shè)計(jì)模式》中提倡的針對(duì)接口編程而不是針對(duì)實(shí)現(xiàn)編程就是充分利用多態(tài)的典型例子浓镜。定義功能和組件時(shí)定義接口,實(shí)現(xiàn)可以留到之后的流程中劲厌。同時(shí)一個(gè)接口可以有多個(gè)實(shí)現(xiàn)哄啄,甚至于完全可以在一個(gè)設(shè)計(jì)中同時(shí)使用一個(gè)接口的多種實(shí)現(xiàn)。 -
多態(tài)實(shí)現(xiàn)原理
多態(tài)允許具體訪問時(shí)實(shí)現(xiàn)方法的動(dòng)態(tài)綁定风范。Java對(duì)于動(dòng)態(tài)綁定的實(shí)現(xiàn)主要依賴于方法表咨跌,通過繼承和接口的多態(tài)實(shí)現(xiàn)有所不同。
繼承:在執(zhí)行某個(gè)方法時(shí)硼婿,在方法區(qū)中找到該類的方法表锌半,再確認(rèn)該方法在方法表中的偏移量,找到該方法后如果被重寫則直接調(diào)用寇漫,否則認(rèn)為沒有重寫父類該方法刊殉,這時(shí)會(huì)按照繼承關(guān)系搜索父類的方法表中該偏移量對(duì)應(yīng)的方法殉摔。
接口:Java 允許一個(gè)類實(shí)現(xiàn)多個(gè)接口,從某種意義上來說相當(dāng)于多繼承冗澈,這樣同一個(gè)接口的的方法在不同類方法表中的位置就可能不一樣了钦勘。所以不能通過偏移量的方法,而是通過搜索完整的方法表亚亲。
tips:因?yàn)槊看谓涌谡{(diào)用都要搜索方法表彻采,所以從效率上來說,接口方法的調(diào)用總是慢于類方法的調(diào)用的捌归。
《Java 多態(tài)的實(shí)現(xiàn)機(jī)制》
《Java技術(shù)——多態(tài)的實(shí)現(xiàn)原理》
弄清了多態(tài)的原理才能搞清楚如下現(xiàn)象:
當(dāng)父類和子類有相同的成員變量肛响,多態(tài)下訪問的是父類的成員變量(不管是靜態(tài)還是非靜態(tài)的成員變量)。
當(dāng)子類重寫父類方法惜索,多態(tài)調(diào)用方法時(shí)(非靜態(tài)的成員方法)訪問的是子類的成員方法特笋,(靜態(tài)的成員方法)訪問的是父類的靜態(tài)方法。
3.對(duì)象封裝的原則是什么?
在面向?qū)ο蟪淌皆O(shè)計(jì)方法中巾兆,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實(shí)現(xiàn)細(xì)節(jié)部份包裝猎物、隱藏起來的方法。封裝可以被認(rèn)為是一個(gè)保護(hù)屏障角塑,防止該類的代碼和數(shù)據(jù)被外部類定義的代碼隨機(jī)訪問蔫磨。要訪問該類的代碼和數(shù)據(jù),必須通過嚴(yán)格的接口控制圃伶。封裝最主要的功能在于我們能修改自己的實(shí)現(xiàn)代碼堤如,而不用修改那些調(diào)用我們代碼的程序片段。適當(dāng)?shù)姆庋b可以讓程式碼更容易理解與維護(hù)窒朋,也加強(qiáng)了程式碼的安全性搀罢。
- 修改屬性的可見性來限制對(duì)屬性的訪問(一般限制為private);
- 對(duì)每個(gè)值屬性提供對(duì)外的公共方法訪問侥猩,也就是創(chuàng)建一對(duì)賦取值方法榔至,用于對(duì)私有屬性的訪問;
4.獲得一個(gè)類的類對(duì)象有哪些方式欺劳?
- 1.通過對(duì)象的getClass方法進(jìn)行獲取洛退。這種方式需要具體的類和該類的對(duì)象,以及調(diào)用getClass方法杰标。
- 2.任何數(shù)據(jù)類型(包括基本數(shù)據(jù)類型)都具備著一個(gè)靜態(tài)的屬性class,通過它可直接獲取到該類型對(duì)應(yīng)的Class對(duì)象彩匕。這種方式要使用具體的類腔剂,然后調(diào)用類中的靜態(tài)屬性class完成,無需調(diào)用方法驼仪,性能更好掸犬。
- 3.通過Class.forName()方法獲取袜漩。這種方式僅需使用類名,就可以獲取該類的Class對(duì)象湾碎,更有利于擴(kuò)展宙攻。
import org.junit.Test;
/**
* 演示獲取Class c對(duì)象的三種方法
*@fileName ReflectGetClass.java
*/
public class ReflectGetClass {
/**
* 法1:通過對(duì)象---對(duì)象.getClass()來獲取c(一個(gè)Class對(duì)象)
*/
@Test
public void get1(){
Person p=new Person("Jack", 23);
Class c=p.getClass();//來自O(shè)bject方法
}
/**
* 法2:通過類(類型)---任何數(shù)據(jù)類型包括(基本數(shù)據(jù)類型)都有一個(gè)靜態(tài)的屬性class ,他就是c 一個(gè)Class對(duì)象
*/
@Test
public void get2(){
Class c=Person.class;
Class c2=int.class;
}
/**
* 法3:通過字符串(類全名 )---能夠?qū)崿F(xiàn)解耦:Class.forName(str)
*/
@Test
public void get3(){
try {
Class c=Class.forName("cn.hncu.reflect.test.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
5.重載(Overload)和重寫(Override)的區(qū)別介褥。重載的方法能否根據(jù)返回類型進(jìn)行區(qū)分座掘?
一、重寫(override)
override是重寫(覆蓋)了一個(gè)方法柔滔,以實(shí)現(xiàn)不同的功能溢陪。一般是用于子類在繼承父類時(shí),重寫(重新實(shí)現(xiàn))父類中的方法睛廊。重寫(覆蓋)的規(guī)則:
- 1形真、重寫方法的參數(shù)列表必須完全與被重寫的方法的相同,否則不能稱其為重寫而是重載.
- 2、重寫方法的訪問修飾符一定要大于被重寫方法的訪問修飾符(public>protected>default>private)超全。
- 3咆霜、重寫的方法的返回值必須和被重寫的方法的返回一致;
- 4嘶朱、重寫的方法所拋出的異常必須和被重寫方法的所拋出的異常一致蛾坯,或者是其子類;
- 5见咒、被重寫的方法不能為private偿衰,否則在其子類中只是新定義了一個(gè)方法,并沒s有對(duì)其進(jìn)行重寫改览。
- 6下翎、靜態(tài)方法不能被重寫為非靜態(tài)的方法(會(huì)編譯出錯(cuò))。
二宝当、overload是重載
一般是用于在一個(gè)類內(nèi)實(shí)現(xiàn)若干重載的方法视事,這些方法的名稱相同而參數(shù)形式不同。
重載的規(guī)則: - 1庆揩、在使用重載時(shí)只能通過相同的方法名俐东、不同的參數(shù)形式實(shí)現(xiàn)。不同的參數(shù)類型可以是不同的參數(shù)類型订晌,不同的參數(shù)個(gè)數(shù)虏辫,不同的參數(shù)順序(參數(shù)類型必須不一樣);
- 2锈拨、不能通過訪問權(quán)限砌庄、返回類型、拋出的異常進(jìn)行重載;
- 3娄昆、方法的異常類型和數(shù)目不會(huì)對(duì)重載造成影響佩微;
多態(tài)的概念比較復(fù)雜,有多種意義的多態(tài)萌焰,一個(gè)有趣但不嚴(yán)謹(jǐn)?shù)恼f法是:繼承是子類使用父類的方法哺眯,而多態(tài)則是父類使用子類的方法。一般扒俯,我們使用多態(tài)是為了避免在父類里大量重載引起代碼臃腫且難于維護(hù)奶卓。
《java編程思想》中很好的回答了不能以返回值來區(qū)分重載方法:
void f(){ }
void f(){ return 1; }
假如有int x=f()
,這里是可以區(qū)分重載方法,但有時(shí)候并不需要返回值陵珍,只是調(diào)用方法寝杖,那么像這樣的f()
就讓人無法理解了。
6.說出幾條 Java 中方法重載的最佳實(shí)踐互纯?
- a)不要重載這樣的方法:一個(gè)方法接收 int 參數(shù)瑟幕,而另個(gè)方法接收 Integer 參數(shù)。
- b)不要重載參數(shù)數(shù)量一致留潦,而只是參數(shù)順序不同的方法只盹。
- c)如果重載的方法參數(shù)個(gè)數(shù)多于 5 個(gè),采用可變參數(shù)兔院。
二殖卑、抽象類和接口
1.抽象類和接口的區(qū)別
- 一、相似性
- 接口和抽象類都不能被實(shí)例化坊萝,它們都位于繼承樹的頂端孵稽,用于被其他類實(shí)現(xiàn)和繼承。
- 接口和抽象類都可以包含抽象方法十偶,實(shí)現(xiàn)接口或繼承抽象類的普通子類都必須實(shí)現(xiàn)這些抽象方法菩鲜。
二、接口和抽象類的區(qū)別 - 抽象類中的方法可以有方法體惦积,就是能實(shí)現(xiàn)方法的具體功能接校,但是接口中的方法不行。
- 抽象類中的成員變量可以是各種類型的狮崩,而接口中的成員變量只能是 public static final (代碼里不用寫蛛勉,隱式包含有)類型的。
- 接口中不能含有靜態(tài)代碼塊以及靜態(tài)方法(用 static 修飾的方法)睦柴,而抽象類是可以有靜態(tài)代碼塊和靜態(tài)方法诽凌。
- 一個(gè)類只能繼承一個(gè)抽象類,而一個(gè)類卻可以實(shí)現(xiàn)多個(gè)接口坦敌。
接口是隱式抽象的皿淋,當(dāng)聲明一個(gè)接口類的時(shí)候招刹,不必使用abstract關(guān)鍵字。
接口中每一個(gè)方法也是隱式抽象的窝趣,聲明時(shí)同樣不需要abstract關(guān)鍵字。
接口中的方法都是公有的(隱式就是public)训柴。
接口可以繼承接口哑舒。
抽象類可以實(shí)現(xiàn)(implements)接口
抽象類可繼承具體類。
抽象類中可以有靜態(tài)的main方法幻馁。
備注:只要明白了接口和抽象類的本質(zhì)和作用洗鸵,這些問題都很好回答,你想想仗嗦,如果你是java語言的設(shè)計(jì)者膘滨,你是否會(huì)提供這樣的支持,如果不提供的話稀拐,有什么理由嗎火邓?如果你沒有道理不提供,那答案就是肯定的了德撬。只有記住抽象類與普通類的唯一區(qū)別就是不能創(chuàng)建實(shí)例對(duì)象和允許有abstract方法铲咨。
2.java接口的基本概念,是否可繼承蜓洪,以及優(yōu)點(diǎn)纤勒?
接口(Interface),在JAVA編程語言中是一個(gè)抽象類型隆檀,是抽象方法的集合摇天。接口通常以interface來聲明。一個(gè)類通過繼承接口的方式恐仑,從而來繼承接口的抽象方法泉坐。如果一個(gè)類只由抽象方法和全局常量組成,那么這種情況下不會(huì)將其定義為一個(gè)抽象類菊霜。只會(huì)定義為一個(gè)接口坚冀,所以接口嚴(yán)格的來講屬于一個(gè)特殊的類,而這個(gè)類里面只有抽象方法和全局常量鉴逞,就連構(gòu)造方法也沒有记某。
- 一個(gè)接口可以繼承多個(gè)接口.
interface C extends A, B {}
是可以的. - 一個(gè)類可以實(shí)現(xiàn)多個(gè)接口:
class D implements A,B,C{}
- 但是一個(gè)類只能繼承一個(gè)類,不能繼承多個(gè)類
class B extends A{}
- 在繼承類的同時(shí),也可以繼承接口:
class E extends D implements A,B,C{}
這也正是選擇用接口而不是抽象類的原因
3、接口的優(yōu)點(diǎn)或者說面向接口編程的思想是什么(這里要結(jié)合運(yùn)行時(shí)多態(tài)更好理解)
在系統(tǒng)分析和架構(gòu)中构捡,分清層次和依賴關(guān)系液南,每個(gè)層次不是直接向其上層提供服務(wù)(即不是直接實(shí)例化在上層中),而是通過定義一組接口勾徽,僅向上層暴露其接口功能滑凉,上層對(duì)于下層僅僅是接口依賴,而不依賴具體類。
好處:首先對(duì)系統(tǒng)靈活性大有好處畅姊。當(dāng)下層需要改變時(shí)咒钟,只要接口及接口功能不變,則上層不用做任何修改若未。甚至可以在不改動(dòng)上層代碼時(shí)將下層整個(gè)替換掉朱嘴。接口體現(xiàn)的是一種規(guī)范和實(shí)現(xiàn)分離的設(shè)計(jì)哲學(xué),充分利用接口可以極好地降低程序各模塊之間的耦合粗合,從而提高系統(tǒng)的可擴(kuò)展性和可維護(hù)性萍嬉。基于這種原則隙疚,通常推薦“面向接口”編程壤追,而不是面向?qū)崿F(xiàn)類編程,希望通過面向接口編程來降低程序的耦合供屉。
總的來說就是:降低程序耦合度行冰,提高系統(tǒng)的可擴(kuò)展性和維護(hù)性。
三贯卦、繼承
1资柔、繼承(Inheritance)與聚合(Aggregation)的區(qū)別在哪里
2、繼承和組合之間有什么不同
- 如果存在一種IS-A的關(guān)系(比如Bee“是一個(gè)”Insect)撵割,并且一個(gè)類需要向另一個(gè)類暴露所有的方法接口贿堰,那么更應(yīng)該用繼承的機(jī)制。
- 如果存在一種HAS-A的關(guān)系(比如Bee“有一個(gè)”attack功能)啡彬,那么更應(yīng)該運(yùn)用組合羹与。
3、為什么類只能單繼承庶灿,接口可以多繼承
首先纵搁,類的多繼承有缺點(diǎn):
第一,如果一個(gè)類繼承多個(gè)父類往踢,如果父類中的方法名如果相同腾誉,那么就會(huì)產(chǎn)生歧義。
第二峻呕,如果父類中的方法同名利职,子類中沒有覆蓋,同樣會(huì)產(chǎn)生上面的錯(cuò)誤瘦癌。
但是接口就設(shè)計(jì)成多繼承猪贪,是因?yàn)榻涌诳梢员苊馍鲜鰡栴}:
首先,接口中的只有抽象方法和靜態(tài)常量讯私。對(duì)于一個(gè)類實(shí)現(xiàn)多個(gè)接口的情況和一個(gè)接口繼承多個(gè)接口的情況热押,因?yàn)榻涌谥挥谐橄蠓椒ㄎ骺唧w方法只能由實(shí)現(xiàn)接口的類實(shí)現(xiàn)(也是因?yàn)閷?shí)現(xiàn)類一定會(huì)覆蓋接口中的方法),在調(diào)用的時(shí)候始終只會(huì)調(diào)用實(shí)現(xiàn)類(也就是子類覆蓋的方法)的方法(不存在歧義)桶癣,因此不存在 多繼承的第二個(gè)缺點(diǎn)拥褂;而又因?yàn)榻涌谥挥徐o態(tài)的常量,但是由于靜態(tài)變量是在編譯期決定調(diào)用關(guān)系的牙寞,即使存在一定的沖突也會(huì)在編譯時(shí)提示出錯(cuò)肿仑;而引用靜態(tài)變量一般直接使用類名或接口名,從而避免產(chǎn)生歧義碎税,因此也不存在多繼承的第一個(gè)缺點(diǎn)。
4馏锡、存在兩個(gè)類雷蹂,C 繼承 B,B 繼承 A杯道,能將 B 轉(zhuǎn)換為 C 么匪煌?如 C = (C) B
不能轉(zhuǎn)換,測試代碼報(bào)錯(cuò):
Exception in thread "main" java.lang.ClassCastException: interfaceDemo.B cannot be cast to interfaceDemo.C
5党巾、如果類 a 繼承類 b萎庭,實(shí)現(xiàn)接口c,而類 b 和接口 c 中定義了同名變量齿拂,請(qǐng)問會(huì)出現(xiàn)什么問題
四驳规、泛型
1、泛型的存在是用來解決什么問題署海?
首先需要明確泛型的概念吗购,泛型(Generics )是把類型參數(shù)化,運(yùn)用于類砸狞、接口捻勉、方法中,可以通過執(zhí)行泛型類型調(diào)用 分配一個(gè)類型刀森,將用分配的具體類型替換泛型類型踱启。然后,所分配的類型將用于限制容器內(nèi)使用的值研底,這樣就無需進(jìn)行類型轉(zhuǎn)換埠偿,還可以在編譯時(shí)提供更強(qiáng)的類型檢查。
總結(jié)來說就是:
(1)消除顯示的強(qiáng)制類型轉(zhuǎn)換飘哨,提高代碼復(fù)用
(2)提供更強(qiáng)的類型檢查胚想,避免運(yùn)行時(shí)的ClassCastException
。
這個(gè)問題產(chǎn)生的背景是針對(duì)容器中芽隆,基于繼承的泛型實(shí)現(xiàn)會(huì)帶來兩個(gè)問題浊服,請(qǐng)看代碼:
public class ArrayList {
public Object get(int i) { ... }
public void add(Object o) { ... }
...
private Object[] elementData;
}
基于繼承的泛型實(shí)現(xiàn)會(huì)帶來兩個(gè)問題:第一個(gè)問題是有關(guān)get()
方法的统屈,我們每次調(diào)用get()
方法都會(huì)返回一個(gè)Object
對(duì)象,每一次都要強(qiáng)制類型轉(zhuǎn)換為我們需要的類型牙躺,這樣會(huì)顯得很麻煩愁憔;第二個(gè)問題是有關(guān)add方法的,假如我們往聚合了String
對(duì)象的ArrayList
中加入一個(gè)File
對(duì)象孽拷,編譯器不會(huì)產(chǎn)生任何錯(cuò)誤提示吨掌,而這不是我們想要的。所以脓恕,從Java 5開始膜宋,ArrayList在使用時(shí)可以加上一個(gè)類型參數(shù)(type parameter),這個(gè)類型參數(shù)用來指明ArrayList中的元素類型炼幔。類型參數(shù)的引入解決了以上提到的兩個(gè)問題秋茫,如以下代碼所示:
ArrayList<String> s = new ArrayList<String>();
s.add("abc");
String s = s.get(0); //無需進(jìn)行強(qiáng)制轉(zhuǎn)換
s.add(123); //編譯錯(cuò)誤,只能向其中添加String對(duì)象
2乃秀、泛型的常用特點(diǎn)肛著?
這里其實(shí)問的就是泛型在使用過程中遵循的相關(guān)規(guī)范。類型參數(shù)(又稱類型變量)用作占位符跺讯,指示在運(yùn)行時(shí)為類分配類型枢贿。根據(jù)需要,可能有一個(gè)或多個(gè)類型參數(shù)刀脏,并且可以用于整個(gè)類局荚。根據(jù)慣例,類型參數(shù)是單個(gè)大寫字母火本,該字母用于指示所定義的參數(shù)類型危队。下面列出每個(gè)用例的標(biāo)準(zhǔn)類型參數(shù):
E:元素
K:鍵
N:數(shù)字
T:類型
V:值
S、U钙畔、V 等:多參數(shù)情況中的第 2茫陆、3、4 個(gè)類型
? 表示不確定的java類型(無限制通配符類型)
五擎析、匿名內(nèi)部類
內(nèi)部類(nested classes)簿盅,面向?qū)ο蟪绦蛟O(shè)計(jì)中,可以在一個(gè)類的內(nèi)部定義另一個(gè)類揍魂。嵌套類分為兩種桨醋,即靜態(tài)嵌套類和非靜態(tài)嵌套類。靜態(tài)嵌套類使用很少现斋,最重要的是非靜態(tài)嵌套類喜最,也即是被稱作為內(nèi)部類(inner)。內(nèi)部類是JAVA語言的主要附加部分庄蹋。內(nèi)部類幾乎可以處于一個(gè)類內(nèi)部任何位置瞬内,可以與實(shí)例變量處于同一級(jí)迷雪,或處于方法之內(nèi),甚至是一個(gè)表達(dá)式的一部分虫蝶。
1章咧、匿名內(nèi)部類是否可以繼承其它類?是否可以實(shí)現(xiàn)接口能真?
使用匿名內(nèi)部類我們必須要繼承一個(gè)父類或者實(shí)現(xiàn)一個(gè)接口赁严,當(dāng)然也僅能只繼承一個(gè)父類或者實(shí)現(xiàn)一個(gè)接口。同時(shí)它也是沒有class關(guān)鍵字粉铐,這是因?yàn)槟涿麅?nèi)部類是直接使用new來生成一個(gè)對(duì)象的引用疼约,當(dāng)然這個(gè)引用是隱式的。不可以繼承其它類和實(shí)現(xiàn)接口蝙泼。
2忆谓、內(nèi)部類分為幾種?
- 成員內(nèi)部類踱承,在一個(gè)類(外部類)中直接定義的內(nèi)部類;
- 局部內(nèi)部類哨免,在一個(gè)方法(外部類的方法)中定義的內(nèi)部類;
- 匿名內(nèi)部類茎活,
1.成員內(nèi)部類
可以訪問它的外部類的所有成員變量和方法,不管是靜態(tài)的還是非靜態(tài)的都可以琢唾。
在外部類里面創(chuàng)建成員內(nèi)部類的實(shí)例:this.new B()载荔;
在外部類之外創(chuàng)建內(nèi)部類的實(shí)例:(new Test1()).new B().go();
2.局部內(nèi)部類
定義在方法中,比方法的范圍還小采桃。是內(nèi)部類中最少用到的一種類型懒熙。像局部變量一樣,不能被public
,protected
, private
和static
修飾普办。只能訪問方法中定義的final類型的局部變量工扎。
方法內(nèi)部類在方法中定義,所以只能在方法中使用衔蹲,即只能在方法當(dāng)中生成方法內(nèi)部類的實(shí)例并且調(diào)用其方法肢娘。
3.匿名內(nèi)部類
沒有名字的局部內(nèi)部類,不使用關(guān)鍵字class, extends, implements, 沒有構(gòu)造方法舆驶。什么情況下需要使用匿名內(nèi)部類瓜浸?如果滿足下面的一些條件耳奕,使用匿名內(nèi)部類是比較合適的:
- 只用到類的一個(gè)實(shí)例。
- 類在定義后馬上用到。
- 類非常心酆!(SUN推薦是在4行代碼以下)
- 給類命名并不會(huì)導(dǎo)致你的代碼更容易被理解。
在使用匿名內(nèi)部類時(shí)枣氧,要記住以下幾個(gè)原則:
- 匿名內(nèi)部類不能有構(gòu)造方法。
- 匿名內(nèi)部類不能定義任何靜態(tài)成員网缝、方法和類。
- 匿名內(nèi)部類不能是public,protected,private,static亮隙。
- 只能創(chuàng)建匿名內(nèi)部類的一個(gè)實(shí)例途凫。
- 一個(gè)匿名內(nèi)部類一定是在new的后面,用其隱含實(shí)現(xiàn)一個(gè)接口或?qū)崿F(xiàn)一個(gè)類溢吻。
- 因匿名內(nèi)部類為局部內(nèi)部類维费,所以局部內(nèi)部類的所有限制都對(duì)其生效。
//實(shí)例代碼
interface innerclass{
public void print();
}
public class Main {
public static void main(String[] args) {
innerclass i = new innerclass() {
@Override
public void print() {
System.out.println("匿名內(nèi)部類");
// TODO Auto-generated method stub
}
};
i.print();
}
}
匿名內(nèi)部類的高頻使用場景是在多線程下(靈活使用箭頭函數(shù)語法糖):
// Java 8之前:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8, too much code for too little to do");
}
}).start();
//Java 8方式:
new Thread(() -> System.out.println("In Java8, Lambda expression!!") ).start();
3促王、內(nèi)部類可以引用它的包含類(外部類)的成員嗎犀盟?
內(nèi)部類可以直接訪問外部類的成員屬性
4、請(qǐng)說一下 Java 中為什么要引入內(nèi)部類蝇狼?還有匿名內(nèi)部類阅畴?
- 內(nèi)部類對(duì)象可以訪問創(chuàng)建它的對(duì)象的實(shí)現(xiàn),包括私有數(shù)據(jù)迅耘;
- 內(nèi)部類不為同一包的其他類所見贱枣,具有很好的封裝性;
- 使用內(nèi)部類可以很方便的編寫事件驅(qū)動(dòng)程序颤专;
- 匿名內(nèi)部類可以方便的定義運(yùn)行時(shí)回調(diào)纽哥;
- 內(nèi)部類可以方便的定義