開(kāi)刷BAT等大廠最全面試題集錦

(一) java基礎(chǔ)面試知識(shí)點(diǎn)

1.java中==和equals和hashCode的區(qū)別

答:首先回答的是三個(gè)定義

? ? ? 1> ==是一個(gè)運(yùn)算符號(hào),是用來(lái)比較兩個(gè)變量是否相等

? ? ? 2> equals是Objec類的方法,用于比較兩個(gè)對(duì)象是否相等,默認(rèn)Object類的equals方法是比較兩個(gè)對(duì)象的地址,跟==的結(jié)果一樣。Object的equals方法如下:

????public?boolean?equals(Object?obj)?{??

????????return?(this?==?obj);??

????}??

? ? ?3>?hashCode也是Object類的一個(gè)方法。返回一個(gè)離散的int型整數(shù)。在集合類操作中使用,為了提高查詢速度。(HashMap,HashSet等)

接下來(lái)回答的是三者的區(qū)別

? ? 1>如果比較的是基本數(shù)據(jù)類型,那就直接用==這個(gè)運(yùn)算符號(hào)來(lái)比較他們的值

? ? 2>如果比較的是符合數(shù)據(jù)類型,就是類,

? ? ? ? 這個(gè)時(shí)候如果用:(==)進(jìn)行比較的時(shí)候,比較的是在內(nèi)存中的存放地址,(除非是同一個(gè)new出來(lái)的對(duì)象,他們的地址是一樣的),如果用equals進(jìn)行比較,要分為兩種情況,第一種如果object類中的equals方法并沒(méi)有被其他(String,integer,date)這些類覆蓋,那么比較的是對(duì)象的內(nèi)存地址,如果被覆蓋了比較的是在比較兩個(gè)對(duì)象的value值是否相等,在接下來(lái)是hashcode的理解,如果兩個(gè)對(duì)象根據(jù)equals()方法比較是相等,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hasnCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果.如果兩個(gè)對(duì)象根據(jù)equals()方法比較是不相等的,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashcode方法,則不一定要產(chǎn)生相同的結(jié)果

接下來(lái)還可以說(shuō)明注意點(diǎn)

當(dāng)在代碼中需要覆蓋equals時(shí)總要覆蓋hashCode,如果不進(jìn)行覆蓋的話就會(huì)違反objecthashCode的通用約定,從而導(dǎo)致該類無(wú)法結(jié)合所有從而導(dǎo)致該類無(wú)法結(jié)合所有基于散列的集合一起正常運(yùn)作,這樣的集合包括HashMap、HashSet和Hashtable在應(yīng)用程序的執(zhí)行期間,只要對(duì)象的equals方法的比較操作所用到的信息沒(méi)有被修改,那么對(duì)這同一個(gè)對(duì)象調(diào)用多次,hashCode方法都必須始終如一地返回同一個(gè)整數(shù)。在同一個(gè)應(yīng)用程序的多次執(zhí)行過(guò)程中,每次執(zhí)行所返回的整數(shù)可以不一致。

如果兩個(gè)對(duì)象根據(jù)equals()方法比較是相等的,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果。

如果兩個(gè)對(duì)象根據(jù)equals()方法比較是不相等的,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashCode方法,則不一定要產(chǎn)生相同的整數(shù)結(jié)果。但是程序員應(yīng)該知道,給不相等的對(duì)象產(chǎn)生截然不同的整數(shù)結(jié)果,有可能提高散列表的性能。

2.int、char、long各占多少字節(jié)數(shù)

答:1字節(jié): byte , boolean

? ? ?2字節(jié): short , char

? ? ?4字節(jié): int , float

? ? ?8字節(jié): long , double?

注:1字節(jié)(byte)=8位(bits)


3.int與integer的區(qū)別

答:1、Integer是int的包裝類,int則是java的一種基本數(shù)據(jù)類型?

????2、Integer變量必須實(shí)例化后才能使用,而int變量不需要?

????3、Integer實(shí)際是對(duì)象的引用,當(dāng)new一個(gè)Integer時(shí),實(shí)際上是生成一個(gè)指針指向此對(duì)象;而int則是直接存儲(chǔ)數(shù)據(jù)值?

? ?4、Integer的默認(rèn)值是null,int的默認(rèn)值是0

關(guān)于Integer和int的比較

1、由于Integer變量實(shí)際上是對(duì)一個(gè)Integer對(duì)象的引用,所以兩個(gè)通過(guò)new生成的Integer變量永遠(yuǎn)是不相等的(因?yàn)閚ew生成的是兩個(gè)對(duì)象,其內(nèi)存地址不同)。

Integer i =newInteger(100);

Integer j =newInteger(100);

System.out.print(i == j); //false

2、Integer變量和int變量比較時(shí),只要兩個(gè)變量的值是向等的,則結(jié)果為true(因?yàn)榘b類Integer和基本數(shù)據(jù)類型int比較時(shí),java會(huì)自動(dòng)拆包裝為int,然后進(jìn)行比較,實(shí)際上就變?yōu)閮蓚€(gè)int變量的比較)

Integer i = newInteger(100);

int j =100;

System.out.print(i == j); //true

3、非new生成的Integer變量和new Integer()生成的變量比較時(shí),結(jié)果為false。(因?yàn)榉莕ew生成的Integer變量指向的是java常量池中的對(duì)象,而new Integer()生成的變量指向堆中新建的對(duì)象,兩者在內(nèi)存中的地址不同)

Integer i =newInteger(100);

Integer j =100;

System.out.print(i == j); //false

4、對(duì)于兩個(gè)非new生成的Integer對(duì)象,進(jìn)行比較時(shí),如果兩個(gè)變量的值在區(qū)間-128到127之間,則比較結(jié)果為true,如果兩個(gè)變量的值不在此區(qū)間,則比較結(jié)果為false

Integer i =100;

Integer j =100;

System.out.print(i == j); //true

Integer i =128;

Integer j =128;

System.out.print(i == j); //false

對(duì)于第4條的原因:

java在編譯Integer i = 100 ;時(shí),會(huì)翻譯成為Integer i = Integer.valueOf(100);,而java API中對(duì)Integer類型的valueOf的定義如下:

publicstaticIntegervalueOf(int i){

assert IntegerCache.high >=127;

if (i >= IntegerCache.low && i <= IntegerCache.high){

return IntegerCache.cache[i + (-IntegerCache.low)];

}

returnnew Integer(i);

}

java對(duì)于-128到127之間的數(shù),會(huì)進(jìn)行緩存,Integer i = 127時(shí),會(huì)將127進(jìn)行緩存,下次再寫Integer j = 127時(shí),就會(huì)直接從緩存中取,就不會(huì)new了

如果有錯(cuò)誤的地方,還請(qǐng)指正。


4.談?wù)剬?duì)java多態(tài)的理解

答:先從定義談起,

1.面向?qū)ο蟮娜筇匦苑謩e是,封裝.繼承.多態(tài)

2.什么是多態(tài),指允許不同類的對(duì)象對(duì)同一消息做出響應(yīng),即同一消息可以根據(jù)發(fā)送對(duì)象的不同而采用多種不同的行為方式

3.實(shí)現(xiàn)多態(tài)的技術(shù)稱為:動(dòng)態(tài)綁定,是指在執(zhí)行期間判斷所引用對(duì)象的實(shí)際類型,根據(jù)其實(shí)際的類型調(diào)用其相應(yīng)的方法

4.多態(tài)的作用:消除類型之間的耦合關(guān)系

多態(tài)的三個(gè)必要條件:

一:要有繼承

二.要有重寫

三.父類應(yīng)用指向子類對(duì)象

多態(tài)的好處:

1.可替換性(substitutability)。多態(tài)對(duì)已存在代碼具有可替換性。例如,多態(tài)對(duì)圓Circle類工作,對(duì)其他任何圓形幾何體,如圓環(huán),也同樣工作。

2.可擴(kuò)充性(extensibility)。多態(tài)對(duì)代碼具有可擴(kuò)充性。增加新的子類不影響已存在類的多態(tài)性、繼承性,以及其他特性的運(yùn)行和操作。實(shí)際上新加子類更容易獲得多態(tài)功能。例如,在實(shí)現(xiàn)了圓錐、半圓錐以及半球體的多態(tài)基礎(chǔ)上,很容易增添球體類的多態(tài)性。

3.接口性(interface-ability)。多態(tài)是超類通過(guò)方法簽名,向子類提供了一個(gè)共同接口,由子類來(lái)完善或者覆蓋它而實(shí)現(xiàn)的。如圖8.3 所示。圖中超類Shape規(guī)定了兩個(gè)實(shí)現(xiàn)多態(tài)的接口方法,computeArea()以及computeVolume()。子類,如Circle和Sphere為了實(shí)現(xiàn)多態(tài),完善或者覆蓋這兩個(gè)接口方法。

4.靈活性(flexibility)。它在應(yīng)用中體現(xiàn)了靈活多樣的操作,提高了使用效率。

5.簡(jiǎn)化性(simplicity)。多態(tài)簡(jiǎn)化對(duì)應(yīng)用軟件的代碼編寫和修改過(guò)程,尤其在處理大量對(duì)象的運(yùn)算和操作時(shí),這個(gè)特點(diǎn)尤為突出和重要。


5.String、StringBuffer、StringBuilder區(qū)別

答:String 字符串常量,Stringbuffer字符串變量(線程安全),Stringbuilder字符串變量(非線程安全)

string和Stringbuffer和stringbuilder最大的區(qū)別在于,string是不可變的對(duì)象,當(dāng)每次為String類型進(jìn)行改變的時(shí)候其實(shí)都是生成了一個(gè)新的string對(duì)象,然后指針指向新的string對(duì)象,但凡生成新對(duì)象都會(huì)對(duì)性能產(chǎn)生影響,特別是當(dāng)無(wú)用的對(duì)象在內(nèi)存中占有特別多數(shù)量的時(shí)候,所以在經(jīng)常改變字符串內(nèi)容的時(shí)候盡量不要string,stringbuffer則是對(duì)自己對(duì)象本身進(jìn)行操作,不會(huì)去生成新的對(duì)象,再改變對(duì)象應(yīng)用

舉個(gè)例子

?String S1 = “This is only a” + “ simple” + “ test”;

?StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

?你會(huì)很驚訝的發(fā)現(xiàn),生成 String S1 對(duì)象的速度簡(jiǎn)直太快了,而這個(gè)時(shí)候 StringBuffer 居然速度上根本一點(diǎn)都不占優(yōu)勢(shì)。其實(shí)這是 JVM 的一個(gè)把戲,在 JVM 眼里,這個(gè)

?String S1 = “This is only a” + “ simple” + “test”; 其實(shí)就是:

?String S1 = “This is only a simple test”; 所以當(dāng)然不需要太多的時(shí)間了。但大家這里要注意的是,如果你的字符串是來(lái)自另外的 String 對(duì)象的話,速度就沒(méi)那么快了,譬如:

String S2 = “This is only a”;

String S3 = “ simple”;

String S4 = “ test”;

String S1 = S2 +S3 + S4;

這時(shí)候 JVM 會(huì)規(guī)規(guī)矩矩的按照原來(lái)的方式去做

由此可以對(duì)比出來(lái)大部分情況下Stringbuffer>String

接下來(lái)是要比較stringbuffer和stringbuilde

首先stringbuilde是一個(gè)可變的字符序列是在5.0的時(shí)候新增的,設(shè)計(jì)的主要作用是為了與stringbuffer的一個(gè)簡(jiǎn)易替換,用在字符串緩沖區(qū)被單個(gè)線程使用的時(shí)候,他兩者的方法基本相同的,總結(jié)下來(lái)stringbuffer多數(shù)用于多線程,stringbuilder多使用單線程

由此可以對(duì)比大部分情況下Stringbuilder>stringbuffer>string


6.什么是內(nèi)部類??jī)?nèi)部類的作用

答:內(nèi)部類的定義,就是在一個(gè)類里面的類,預(yù)支對(duì)應(yīng),包含內(nèi)部類的類稱之為外部類

內(nèi)部類可以分為:成員內(nèi)部類,靜態(tài)內(nèi)部類,方法內(nèi)部類,匿名內(nèi)部類

內(nèi)部類的作用有以下幾點(diǎn):

1. 內(nèi)部類提供了更好的封裝,可以把內(nèi)部類隱藏在外部類之內(nèi),不允許同一個(gè)包中的其他類訪問(wèn)該類

2. 內(nèi)部類的方法可以直接訪問(wèn)外部類的所有數(shù)據(jù),包括私有的數(shù)據(jù)

3. 內(nèi)部類所實(shí)現(xiàn)的功能使用外部類同樣可以實(shí)現(xiàn),只是有時(shí)使用內(nèi)部類更方便

注意點(diǎn):

(1)、內(nèi)部類仍然是一個(gè)獨(dú)立的類,在編譯之后內(nèi)部類會(huì)被編譯成獨(dú)立的.class文件,但是前面冠以外部類的類名和$符號(hào)。

(2)、內(nèi)部類不能用普通的方式訪問(wèn)。內(nèi)部類是外部類的一個(gè)成員,因此內(nèi)部類可以自由地訪問(wèn)外部類的成員變量,無(wú)論是否是private的。

(3)、內(nèi)部類聲明成靜態(tài)的,就不能隨便的訪問(wèn)外部類的成員變量,仍然是只能訪問(wèn)外部類的靜態(tài)成員變量。典型的情況是,內(nèi)部類繼承自某個(gè)類或?qū)崿F(xiàn)某個(gè)接口,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對(duì)象。所以你可以認(rèn)為內(nèi)部類提供了某種進(jìn)入其外圍類的窗口。使用內(nèi)部類最吸引人的原因是:  每個(gè)內(nèi)部類都能獨(dú)立地繼承自一個(gè)(接口的)實(shí)現(xiàn),所以無(wú)論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒(méi)有影響。如果沒(méi)有內(nèi)部類提供的可以繼承多個(gè)具體的或抽象的類的能力,一些設(shè)計(jì)與編程問(wèn)題就很難解決。從這個(gè)角度看,內(nèi)部類使得多重繼承的解決方案變得完整。接口解決了部分問(wèn)題,而內(nèi)部類有效地實(shí)現(xiàn)了“多重繼承”。


7.抽象類和接口區(qū)別

答:

1.抽象類可以提供成員方法.可以是各種成員變量,可以有靜態(tài)代碼塊和方法,一個(gè)類只能繼承一個(gè)抽象類

2.接口只能存在public abstract抽象方法,成員變量中必須使用public static final修飾,不可以含有靜態(tài)代碼塊和靜態(tài)方法,一個(gè)類可以實(shí)現(xiàn)多個(gè)接口


8.抽象類的意義,接口的意義

答:抽象類往往用來(lái)表示在對(duì)問(wèn)題領(lǐng)域進(jìn)行分析,設(shè)計(jì)中得出抽象概念,是對(duì)一系列看上去不同,但本質(zhì)相同的具體概念的抽象,即對(duì)類的抽象,而接口是對(duì)行為的抽象.抽象類是對(duì)整個(gè)類進(jìn)行抽象,包括屬性,行為,但是接口卻是對(duì)類局部(行為)進(jìn)行抽象


9.抽象類與接口的應(yīng)用場(chǎng)景

答:舉個(gè)例子,飛機(jī)和飛鳥他倆的共性都是飛,那么飛機(jī)的類為airplane,飛鳥為bird,那么fly就可以作為一個(gè)抽象類,飛機(jī)和飛鳥繼承抽象類

例如戰(zhàn)斗機(jī),直升飛機(jī),戰(zhàn)斗機(jī)的功能是戰(zhàn)斗,那么戰(zhàn)斗就是一個(gè)接口,直升飛機(jī)的功能是載人,那么載人就是一個(gè)接口,如果出來(lái)一個(gè)航空戰(zhàn)斗機(jī)型號(hào),既要戰(zhàn)斗又要載人,那么就實(shí)現(xiàn)兩個(gè)接口就好了


10.抽象類是否可以沒(méi)有方法和屬性?

答:抽象類可以不含抽象方法


但是含抽象方法的類一定是抽象類

另注:

①java允許類、接口或者成員方法具有抽象屬性,但不允許成員域或構(gòu)造方法具有抽象屬性

②如果一個(gè)類不具有抽象屬性,則不能在該類的類體中定義抽象成員方法


11.泛型中extends和super的區(qū)別

答:請(qǐng)記住PECS原則:生產(chǎn)者(Producer)使用extends,消費(fèi)者(Consumer)使用super。

生產(chǎn)者使用extends

如果你需要一個(gè)列表提供T類型的元素(即你想從列表中讀取T類型的元素),你需要把這個(gè)列表聲明成< extends T>,比如List< extends Integer>,因此你不能往該列表中添加任何元素。

消費(fèi)者使用super

如果需要一個(gè)列表使用T類型的元素(即你想把T類型的元素加入到列表中),你需要把這個(gè)列表聲明成< super T>,比如List< super Integer>,因此你不能保證從中讀取到的元素的類型。

即是生產(chǎn)者,也是消費(fèi)者

如果一個(gè)列表即要生產(chǎn),又要消費(fèi),你不能使用泛型通配符聲明列表,比如List。


12.父類的靜態(tài)方法能否被子類重寫

答::父類的靜態(tài)方法可以被子類繼承,但是不能重寫。

?先是父類代碼:

public?class?Fu?{??

public?static?void?show()?{??

System.out.println("父類的靜態(tài)方法");??

????}??

public?void?method()?{??

System.out.println("父類的一般方法");??

????}??

}??

? ? ?下面是子類代碼:

public?class?Zi?extends?Fu?{??

public?static?void?main(String[]?args)?{??

Fu?fu?=new?Zi();??

????????fu.show();??

????????fu.method();??

????}??

public?static?void?show()?{??

System.out.println("子類的靜態(tài)");??

????}??

public?void?method()?{??

System.out.println("子類的一般方法");??

????}??


}??

? ? ? ?輸出結(jié)果是:

父類的靜態(tài)方法

子類的一般方法


13.進(jìn)程和線程的區(qū)別

:答

進(jìn)程:具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.

線程:進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.

區(qū)別

進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其它進(jìn)程產(chǎn)生影響,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時(shí),耗費(fèi)資源較大,效率要差一些。但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。

1)?簡(jiǎn)而言之,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.

2)?線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。

3)?另外,進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率。

4)?線程在執(zhí)行過(guò)程中與進(jìn)程還是有區(qū)別的。每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。

5)?從邏輯角度來(lái)看,多線程的意義在于一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒(méi)有將多個(gè)線程看做多個(gè)獨(dú)立的應(yīng)用,來(lái)實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配。這就是進(jìn)程和線程的重要區(qū)別。


14.final,finally,finalize的區(qū)別

答:

final:修飾符(關(guān)鍵字)有三種用法:如果修飾類,不可被繼承,如果修飾變量,不可被修改,如果修飾方法,不可被重寫

finally:通常是房子try..........catch....的后面,構(gòu)造總是執(zhí)行代碼塊,意味著無(wú)論程序正常執(zhí)行還是發(fā)生異常,這里面的代碼只要jvm不關(guān)閉都能執(zhí)行,可以將釋放外部資源的代碼卸載finally塊中

finalize:object類中定義的方法,java中允許使用finalize()方法在垃圾收集齊將對(duì)象從內(nèi)存中清楚出去之前做必要的清理工作,這個(gè)方法是由垃圾收集器在銷毀對(duì)象前調(diào)用的,通過(guò)重寫finalize()方法可以整理系統(tǒng)資源或者執(zhí)行其他清理工作.


15.序列化的方式,serializable和parcelable的區(qū)別

答:

1.在使用內(nèi)存的時(shí)候parcelable類比serializable性能高,所以推薦使用parcelable類

2.serializable在序列化的時(shí)候回產(chǎn)生大量的臨時(shí)變量,從而引起頻繁的GC

3.parcelable不能使用在要要將數(shù)據(jù)存儲(chǔ)在磁盤上的情況,盡管serializable效率地點(diǎn),但是這種情況還是適合使用serializable

4.serializable的實(shí)現(xiàn),只需要繼承serializable即可,這只是給對(duì)象打了一個(gè)標(biāo)記,系統(tǒng)會(huì)自動(dòng)將其序列化

5.parcelable的實(shí)現(xiàn),需要在類中添加一個(gè)靜態(tài)成員變量CREATOR,這個(gè)變量需要繼承Parcelable.Creator


16.靜態(tài)屬性和靜態(tài)方法是否可以被繼承?是否可以被重寫?以及原因?

答:java中靜態(tài)屬性和靜態(tài)方法可以被繼承,但是沒(méi)有被重寫(overwrite)而是被隱藏.

原因:

1). 靜態(tài)方法和屬性是屬于類的,調(diào)用的時(shí)候直接通過(guò)類名.方法名完成對(duì),不需要繼承機(jī)制及可以調(diào)用。如果子類里面定義了靜態(tài)方法和屬性,那么這時(shí)候父類的靜態(tài)方法或?qū)傩苑Q之為"隱藏"。如果你想要調(diào)用父類的靜態(tài)方法和屬性,直接通過(guò)父類名.方法或變量名完成,至于是否繼承一說(shuō),子類是有繼承靜態(tài)方法和屬性,但是跟實(shí)例方法和屬性不太一樣,存在"隱藏"的這種情況。

2). 多態(tài)之所以能夠?qū)崿F(xiàn)依賴于繼承、接口和重寫、重載(繼承和重寫最為關(guān)鍵)。有了繼承和重寫就可以實(shí)現(xiàn)父類的引用指向不同子類的對(duì)象。重寫的功能是:"重寫"后子類的優(yōu)先級(jí)要高于父類的優(yōu)先級(jí),但是“隱藏”是沒(méi)有這個(gè)優(yōu)先級(jí)之分的。

3). 靜態(tài)屬性、靜態(tài)方法和非靜態(tài)的屬性都可以被繼承和隱藏而不能被重寫,因此不能實(shí)現(xiàn)多態(tài),不能實(shí)現(xiàn)父類的引用可以指向不同子類的對(duì)象。非靜態(tài)方法可以被繼承和重寫,因此可以實(shí)現(xiàn)多態(tài)。


17.靜態(tài)內(nèi)部類的設(shè)計(jì)意圖

答:靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類之間存在一個(gè)最大的區(qū)別:非靜態(tài)內(nèi)部類在編譯完成之后會(huì)隱含地保存著一個(gè)引用,該引用是指向創(chuàng)建它的外圍內(nèi),但是靜態(tài)內(nèi)部類卻沒(méi)有。

沒(méi)有這個(gè)引用就意味著:

它的創(chuàng)建是不需要依賴于外圍類的。

它不能使用任何外圍類的非static成員變量和方法。


18.成員內(nèi)部類、靜態(tài)內(nèi)部類、局部?jī)?nèi)部類和匿名內(nèi)部類的理解,以及項(xiàng)目中的應(yīng)用

答:內(nèi)部類

內(nèi)部類,即定義在一個(gè)類的內(nèi)部的類。為什么有內(nèi)部類呢?

我們知道,在java中類是單繼承的,一個(gè)類只能繼承另一個(gè)具體類或抽象類(可以實(shí)現(xiàn)多個(gè)接口)。這種設(shè)計(jì)的目的是因?yàn)樵诙嗬^承中,當(dāng)多個(gè)父類中有重復(fù)的屬性或者方法時(shí),子類的調(diào)用結(jié)果會(huì)含糊不清,因此用了單繼承。

而使用內(nèi)部類的原因是:每個(gè)內(nèi)部類都能獨(dú)立地繼承一個(gè)(接口的)實(shí)現(xiàn),所以無(wú)論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒(méi)有影響。

在我們程序設(shè)計(jì)中有時(shí)候會(huì)存在一些使用接口很難解決的問(wèn)題,這個(gè)時(shí)候我們可以利用內(nèi)部類提供的、可以繼承多個(gè)具體的或者抽象的類的能力來(lái)解決這些程序設(shè)計(jì)問(wèn)題。可以這樣說(shuō),接口只是解決了部分問(wèn)題,而內(nèi)部類使得多重繼承的解決方案變得更加完整。

靜態(tài)內(nèi)部類

說(shuō)靜態(tài)內(nèi)部類之前,先了解下成員內(nèi)部類(非靜態(tài)的內(nèi)部類)。

成員內(nèi)部類

成員內(nèi)部類也是最普通的內(nèi)部類,它是外圍類的一個(gè)成員,所以它可以無(wú)限制的訪問(wèn)外圍類的所有成員屬性和方法,盡管是private的,但是外圍類要訪問(wèn)內(nèi)部類的成員屬性和方法則需要通過(guò)內(nèi)部類實(shí)例來(lái)訪問(wèn)。

在成員內(nèi)部類中要注意兩點(diǎn):

成員內(nèi)部類中不能存在任何static的變量和方法;

成員內(nèi)部類是依附于外圍類的,所以只有先創(chuàng)建了外圍類才能夠創(chuàng)建內(nèi)部類。

靜態(tài)內(nèi)部類

靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類之間存在一個(gè)最大的區(qū)別:非靜態(tài)內(nèi)部類在編譯完成之后會(huì)隱含地保存著一個(gè)引用,該引用是指向創(chuàng)建它的外圍內(nèi),但是靜態(tài)內(nèi)部類卻沒(méi)有。

沒(méi)有這個(gè)引用就意味著:

它的創(chuàng)建是不需要依賴于外圍類的。

它不能使用任何外圍類的非static成員變量和方法。

其它兩種內(nèi)部類:局部?jī)?nèi)部類和匿名內(nèi)部類

局部?jī)?nèi)部類

局部?jī)?nèi)部類是嵌套在方法和作用于內(nèi)的,對(duì)于這個(gè)類的使用主要是應(yīng)用與解決比較復(fù)雜的問(wèn)題,想創(chuàng)建一個(gè)類來(lái)輔助我們的解決方案,到那時(shí)又不希望這個(gè)類是公共可用的,所以就產(chǎn)生了局部?jī)?nèi)部類,局部?jī)?nèi)部類和成員內(nèi)部類一樣被編譯,只是它的作用域發(fā)生了改變,它只能在該方法和屬性中被使用,出了該方法和屬性就會(huì)失效。

匿名內(nèi)部類

1、匿名內(nèi)部類是沒(méi)有訪問(wèn)修飾符的。

2、new 匿名內(nèi)部類,這個(gè)類首先是要存在的。

3、當(dāng)所在方法的形參需要被匿名內(nèi)部類使用,那么這個(gè)形參就必須為final。

4、匿名內(nèi)部類沒(méi)有明面上的構(gòu)造方法,編譯器會(huì)自動(dòng)生成一個(gè)引用外部類的構(gòu)造方法。


19.談?wù)剬?duì)kotlin的理解

答:2017年谷歌I/O大會(huì)的最后,谷歌宣布將Kotlin語(yǔ)言作為安卓開(kāi)發(fā)的一級(jí)編程語(yǔ)言。Kotlin由JetBrains公司開(kāi)發(fā),與Java 100%互通,并具備諸多Java尚不支持的新特性。谷歌稱還將與JetBrains公司合作,為Kotlin設(shè)立一個(gè)非盈利基金會(huì)。

Kotlin的文件擴(kuò)展名為.kt和.kts,使用Kotlin,你可以用更少的代碼獲得更多的功能。 而你寫的代碼越少,你犯的錯(cuò)誤就越少。除此以外,他還有如下特點(diǎn):

1> Kotlin編譯為JVM字節(jié)碼或JavaScript,方便在沒(méi)有JVM的設(shè)備上運(yùn)行。

2> Kotlin程序可以使用所有現(xiàn)有的Java框架和庫(kù),也就是說(shuō)所有的現(xiàn)有程序不需要更改就可以直接被調(diào)用。

3> Kotlin可以輕松學(xué)習(xí),平易近人。它的規(guī)則及其簡(jiǎn)單,語(yǔ)法規(guī)則少,易于學(xué)習(xí)。

4> Kotlin是開(kāi)放源碼,沒(méi)有收費(fèi)。雖然java也是開(kāi)源語(yǔ)言,但是相比于其他的非開(kāi)源的還是有一定優(yōu)勢(shì)的。

5> 將Java自動(dòng)轉(zhuǎn)換為Kotlin,有強(qiáng)迫癥的也可以這么搞,不用逼死強(qiáng)迫癥的。

6> Kotlin的空安全性很好

7> 空安全 Null Safety- 如上節(jié)所述,Kotlin避免了NullPointerException。

8> 擴(kuò)展函數(shù)Extension Functions- Kotlin允許我們擴(kuò)展現(xiàn)有類的功能,而不繼承它們。意味著Kotlin提供了擴(kuò)展具有新功能的類的能力,而無(wú)需繼承類。


20.閉包和局部?jī)?nèi)部類的區(qū)別

答:

閉包就是把函數(shù)以及變量包起來(lái),使得變量的生存周期延長(zhǎng)。閉包跟面向?qū)ο笫且豢脴?shù)上的兩條枝,實(shí)現(xiàn)的功能是等價(jià)的。

局部?jī)?nèi)部類是嵌套在方法和作用于內(nèi)的,對(duì)于這個(gè)類的使用主要是應(yīng)用與解決比較復(fù)雜的問(wèn)題,想創(chuàng)建一個(gè)類來(lái)輔助我們的解決方案,到那時(shí)又不希望這個(gè)類是公共可用的,所以就產(chǎn)生了局部?jī)?nèi)部類,局部?jī)?nèi)部類和成員內(nèi)部類一樣被編譯,只是它的作用域發(fā)生了改變,它只能在該方法和屬性中被使用,出了該方法和屬性就會(huì)失效。

閉包有什么作用:簡(jiǎn)而言之,閉包的作用就是在Outer執(zhí)行完并返回后,閉包使得Javascript的垃圾回收機(jī)制GC不會(huì)收回Outer所占用的資源,因?yàn)镺uter的內(nèi)部函數(shù)Inner的執(zhí)行需要依賴Outer中的變量。

閉包是一個(gè)可調(diào)用的對(duì)象,它記錄了一些信息,這些信息來(lái)自于創(chuàng)建它的作用域。通過(guò)這個(gè)定義,可以看出內(nèi)部類是面向?qū)ο蟮拈]包,因?yàn)樗粌H包含創(chuàng)建內(nèi)部類的作用域的信息,還自動(dòng)擁有一個(gè)指向此外圍類對(duì)象的引用,在此作用域內(nèi),內(nèi)部類有權(quán)操作所有的成員,包括private成員。


21.string 轉(zhuǎn)換成 integer的方式及原理

答:方式直接是用integer.valueOf(String str)這個(gè)方法(注:如果字符串的格式不對(duì),這個(gè)方法會(huì)拋出NumberFormatException)

原理如下:

在Integer類中的定義如下:

public static Integer valueOf(String s) throws NumberFormatException{

????????return new Integer(parseInt(s, 10));

}

這里因?yàn)閜arseInt方法返回的int型的,這里調(diào)用了一個(gè)構(gòu)造函數(shù)產(chǎn)生了一個(gè)新的Integer實(shí)例.

這里關(guān)心的是parseInt方法,該方法代碼如下:

public static int parseInt(String s, int radix)

throws NumberFormatException{

????????if (s == null) {

????????????????throw new NumberFormatException("null");

????????}

????????if (radix < Character.MIN_RADIX) {

????????????????throw new NumberFormatException("radix " + radix +" less than Character.MIN_RADIX");

????????}

????????if (radix > Character.MAX_RADIX) {

????????????????throw new NumberFormatException("radix " + radix +" greater than Character.MAX_RADIX");

????????}

????????int result = 0;

????????boolean negative = false;

????????int i = 0, max = s.length();

????????int limit;

????????int multmin;

????????int digit;

????????if (max > 0) {

????????if (s.charAt(0) == '-') {

????????????????negative = true;

????????????????limit = Integer.MIN_VALUE;

????????????????i++;

????????} else {

????????????????limit = -Integer.MAX_VALUE;

????????}

????????if (i < max) {

????????????digit = Character.digit(s.charAt(i++),radix);

????????????if (digit < 0) {

????????????throw NumberFormatException.forInputString(s);

????????????} else {

????????????????result = -digit;

????????????}

????}

????while (i < max) {

????// Accumulating negatively avoids surprises near MAX_VALUE

????digit = Character.digit(s.charAt(i++),radix);

????if (digit < 0) {

????????throw NumberFormatException.forInputString(s);?

????}

????if (result < multmin) {

????????throw NumberFormatException.forInputString(s);? 異常1

????}

????result *= radix;

????if (result < limit + digit) {

????????throw NumberFormatException.forInputString(s);? 異常2

????}

? ? result -= digit;

????}

????} else {

????????throw NumberFormatException.forInputString(s);

????}

????if (negative) {

????????if (i > 1) {

????????????return result;

????????} else {?/* Only got "-" */

????????????throw NumberFormatException.forInputString(s);

????????}

????} else {

????????return -result;

????????}

}

很顯然,該方法的第二個(gè)參數(shù)表示是基數(shù)(最常用的是十進(jìn)制,還有十六機(jī)制,八進(jìn)制等等).

如果字符串是空指針,直接拋出異常.

如果基礎(chǔ)小于2或者大于36的話,拋出異常(這種情況一般不會(huì)出現(xiàn),因?yàn)槲覀冇玫淖疃嗑褪鞘M(jìn)制的了).

如果是空字符串,也拋出異常,也就是max=0的情況了.

我們來(lái)關(guān)注下面的轉(zhuǎn)換過(guò)程:

這里使用了Character中的靜態(tài)方法digit,這個(gè)方法比較復(fù)雜,這里先說(shuō)明它的功能:對(duì)于給定的基數(shù),如果是合法的字符(可以轉(zhuǎn)化為數(shù)字),返回該數(shù)字值,否則返回-1.比如digit('3',10)返回3,digit('a',10)返回-1.

這段程序看起來(lái)很簡(jiǎn)單,其實(shí)還真不容易看懂,這里先說(shuō)明幾個(gè)局部變量的含義吧:

result:記錄返回值

negative:符號(hào)標(biāo)志

i:字符串位置

s:字符串長(zhǎng)度

limit:界限

multmin:也是一個(gè)界限

digit:當(dāng)前字符表示的數(shù)字

先看第一個(gè)字符是否是'-'號(hào),設(shè)定符號(hào)標(biāo)志negative和極限值limit.

注意到limit一定是一個(gè)負(fù)值.

處理最高位,這里result保存的是負(fù)值,這樣就可以對(duì)正負(fù)數(shù)統(tǒng)一處理.

關(guān)鍵就是這個(gè)while循環(huán)了,第一個(gè)if不用解釋了,肯定是因?yàn)榉欠ㄗ址?

第二個(gè)if語(yǔ)句的含義:如果result小于multmin,會(huì)產(chǎn)生什么結(jié)果呢?

是不是一定會(huì)溢出呢?假設(shè)不會(huì)溢出,就是說(shuō)結(jié)果必須>=limit.

result小于multmin,result至少應(yīng)該位multmin-1,后面有result=result*radix=(multmin-1)*radix=multmin*radix-radix

該值肯定小于limit,其中multmin=limit/radix,注意這里都是負(fù)數(shù).

所以假設(shè)不成里,如果result小于multmin的話,后面一定會(huì)溢出.

如果這里沒(méi)有判斷的話,溢出就麻煩了,正數(shù)也會(huì)變負(fù)數(shù)了.

第三個(gè)if語(yǔ)句的含義:在這條語(yǔ)句以前肯定沒(méi)有溢出,但是有可能加上最后一位digit就溢出了,所以這個(gè)判斷也是必要的.

后面的就比較好理解了,else是表示空字符串"".

如果是負(fù)數(shù)的還要看是否長(zhǎng)度是1,就只是一個(gè)'-'號(hào)的情況.

如果是正數(shù)的話返回相反數(shù)就可以了.

這里有好多地方都有可能拋出異常,只要看明白了程序就知道這個(gè)異常是那條語(yǔ)句拋出的了,這里考慮溢出異常:異常1和異常2.

Ingeter.Max_VALUE=2147483647

下面的兩條語(yǔ)句在不同的地方拋出異常.

Ingeter.valueOf("2147483648");這個(gè)在異常2拋出的.

Ingeter.valueOf("21474836471");這個(gè)在異常1拋出的.

這里簡(jiǎn)單的分析了String轉(zhuǎn)化為Ingeter的過(guò)程,其實(shí)整個(gè)Ingeter類也就主要是這個(gè)方法了,Byte和Short都是調(diào)用這個(gè)方法的.

看看Byte的代碼:

public static byte parseByte(String s, int radix)

throws NumberFormatException {

int i = Integer.parseInt(s, radix);

if (i < MIN_VALUE || i > MAX_VALUE)

throw new NumberFormatException(

"Value out of range. Value:/"" + s + "/" Radix:" + radix);

return (byte)i;

}

了解這個(gè)方法后就再也不會(huì)為Integer.valueOf()產(chǎn)生的異常感到意外了,特別是在JSP中,因?yàn)閰?shù)都是String型的,轉(zhuǎn)換的時(shí)候動(dòng)不動(dòng)就出現(xiàn)異

常,你該知道怎么回事了吧.

內(nèi)容摘自:https://blog.csdn.net/treeroot/article/details/92923

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容