(一) java基礎面試知識點
1.java中==和equals和hashCode的區(qū)別
答:首先回答的是三個定義
? ? ? 1> ==是一個運算符號,是用來比較兩個變量是否相等
? ? ? 2> equals是Objec類的方法,用于比較兩個對象是否相等,默認Object類的equals方法是比較兩個對象的地址,跟==的結(jié)果一樣。Object的equals方法如下:
????public?boolean?equals(Object?obj)?{??
????????return?(this?==?obj);??
????}??
? ? ?3>?hashCode也是Object類的一個方法。返回一個離散的int型整數(shù)。在集合類操作中使用,為了提高查詢速度。(HashMap,HashSet等)
接下來回答的是三者的區(qū)別
? ? 1>如果比較的是基本數(shù)據(jù)類型,那就直接用==這個運算符號來比較他們的值
? ? 2>如果比較的是符合數(shù)據(jù)類型,就是類,
? ? ? ? 這個時候如果用:(==)進行比較的時候,比較的是在內(nèi)存中的存放地址,(除非是同一個new出來的對象,他們的地址是一樣的),如果用equals進行比較,要分為兩種情況,第一種如果object類中的equals方法并沒有被其他(String,integer,date)這些類覆蓋,那么比較的是對象的內(nèi)存地址,如果被覆蓋了比較的是在比較兩個對象的value值是否相等,在接下來是hashcode的理解,如果兩個對象根據(jù)equals()方法比較是相等,那么調(diào)用這兩個對象中任意一個對象的hasnCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果.如果兩個對象根據(jù)equals()方法比較是不相等的,那么調(diào)用這兩個對象中任意一個對象的hashcode方法,則不一定要產(chǎn)生相同的結(jié)果
接下來還可以說明注意點
當在代碼中需要覆蓋equals時總要覆蓋hashCode,如果不進行覆蓋的話就會違反objecthashCode的通用約定,從而導致該類無法結(jié)合所有從而導致該類無法結(jié)合所有基于散列的集合一起正常運作,這樣的集合包括HashMap、HashSet和Hashtable在應用程序的執(zhí)行期間,只要對象的equals方法的比較操作所用到的信息沒有被修改,那么對這同一個對象調(diào)用多次,hashCode方法都必須始終如一地返回同一個整數(shù)。在同一個應用程序的多次執(zhí)行過程中,每次執(zhí)行所返回的整數(shù)可以不一致。
如果兩個對象根據(jù)equals()方法比較是相等的,那么調(diào)用這兩個對象中任意一個對象的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果。
如果兩個對象根據(jù)equals()方法比較是不相等的,那么調(diào)用這兩個對象中任意一個對象的hashCode方法,則不一定要產(chǎn)生相同的整數(shù)結(jié)果。但是程序員應該知道,給不相等的對象產(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變量必須實例化后才能使用,而int變量不需要?
????3、Integer實際是對象的引用,當new一個Integer時,實際上是生成一個指針指向此對象;而int則是直接存儲數(shù)據(jù)值?
? ?4、Integer的默認值是null,int的默認值是0
關于Integer和int的比較
1、由于Integer變量實際上是對一個Integer對象的引用,所以兩個通過new生成的Integer變量永遠是不相等的(因為new生成的是兩個對象,其內(nèi)存地址不同)。
Integer i =newInteger(100);
Integer j =newInteger(100);
System.out.print(i == j); //false
2、Integer變量和int變量比較時,只要兩個變量的值是向等的,則結(jié)果為true(因為包裝類Integer和基本數(shù)據(jù)類型int比較時,java會自動拆包裝為int,然后進行比較,實際上就變?yōu)閮蓚€int變量的比較)
Integer i = newInteger(100);
int j =100;
System.out.print(i == j); //true
3、非new生成的Integer變量和new Integer()生成的變量比較時,結(jié)果為false。(因為非new生成的Integer變量指向的是java常量池中的對象,而new Integer()生成的變量指向堆中新建的對象,兩者在內(nèi)存中的地址不同)
Integer i =newInteger(100);
Integer j =100;
System.out.print(i == j); //false
4、對于兩個非new生成的Integer對象,進行比較時,如果兩個變量的值在區(qū)間-128到127之間,則比較結(jié)果為true,如果兩個變量的值不在此區(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
對于第4條的原因:
java在編譯Integer i = 100 ;時,會翻譯成為Integer i = Integer.valueOf(100);,而java API中對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對于-128到127之間的數(shù),會進行緩存,Integer i = 127時,會將127進行緩存,下次再寫Integer j = 127時,就會直接從緩存中取,就不會new了
如果有錯誤的地方,還請指正。
4.談談對java多態(tài)的理解
答:先從定義談起,
1.面向?qū)ο蟮娜筇匦苑謩e是,封裝.繼承.多態(tài)
2.什么是多態(tài),指允許不同類的對象對同一消息做出響應,即同一消息可以根據(jù)發(fā)送對象的不同而采用多種不同的行為方式
3.實現(xiàn)多態(tài)的技術稱為:動態(tài)綁定,是指在執(zhí)行期間判斷所引用對象的實際類型,根據(jù)其實際的類型調(diào)用其相應的方法
4.多態(tài)的作用:消除類型之間的耦合關系
多態(tài)的三個必要條件:
一:要有繼承
二.要有重寫
三.父類應用指向子類對象
多態(tài)的好處:
1.可替換性(substitutability)。多態(tài)對已存在代碼具有可替換性。例如,多態(tài)對圓Circle類工作,對其他任何圓形幾何體,如圓環(huán),也同樣工作。
2.可擴充性(extensibility)。多態(tài)對代碼具有可擴充性。增加新的子類不影響已存在類的多態(tài)性、繼承性,以及其他特性的運行和操作。實際上新加子類更容易獲得多態(tài)功能。例如,在實現(xiàn)了圓錐、半圓錐以及半球體的多態(tài)基礎上,很容易增添球體類的多態(tài)性。
3.接口性(interface-ability)。多態(tài)是超類通過方法簽名,向子類提供了一個共同接口,由子類來完善或者覆蓋它而實現(xiàn)的。如圖8.3 所示。圖中超類Shape規(guī)定了兩個實現(xiàn)多態(tài)的接口方法,computeArea()以及computeVolume()。子類,如Circle和Sphere為了實現(xiàn)多態(tài),完善或者覆蓋這兩個接口方法。
4.靈活性(flexibility)。它在應用中體現(xiàn)了靈活多樣的操作,提高了使用效率。
5.簡化性(simplicity)。多態(tài)簡化對應用軟件的代碼編寫和修改過程,尤其在處理大量對象的運算和操作時,這個特點尤為突出和重要。
5.String、StringBuffer、StringBuilder區(qū)別
答:String 字符串常量,Stringbuffer字符串變量(線程安全),Stringbuilder字符串變量(非線程安全)
string和Stringbuffer和stringbuilder最大的區(qū)別在于,string是不可變的對象,當每次為String類型進行改變的時候其實都是生成了一個新的string對象,然后指針指向新的string對象,但凡生成新對象都會對性能產(chǎn)生影響,特別是當無用的對象在內(nèi)存中占有特別多數(shù)量的時候,所以在經(jīng)常改變字符串內(nèi)容的時候盡量不要string,stringbuffer則是對自己對象本身進行操作,不會去生成新的對象,再改變對象應用
舉個例子
?String S1 = “This is only a” + “ simple” + “ test”;
?StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
?你會很驚訝的發(fā)現(xiàn),生成 String S1 對象的速度簡直太快了,而這個時候 StringBuffer 居然速度上根本一點都不占優(yōu)勢。其實這是 JVM 的一個把戲,在 JVM 眼里,這個
?String S1 = “This is only a” + “ simple” + “test”; 其實就是:
?String S1 = “This is only a simple test”; 所以當然不需要太多的時間了。但大家這里要注意的是,如果你的字符串是來自另外的 String 對象的話,速度就沒那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
這時候 JVM 會規(guī)規(guī)矩矩的按照原來的方式去做
由此可以對比出來大部分情況下Stringbuffer>String
接下來是要比較stringbuffer和stringbuilde
首先stringbuilde是一個可變的字符序列是在5.0的時候新增的,設計的主要作用是為了與stringbuffer的一個簡易替換,用在字符串緩沖區(qū)被單個線程使用的時候,他兩者的方法基本相同的,總結(jié)下來stringbuffer多數(shù)用于多線程,stringbuilder多使用單線程
由此可以對比大部分情況下Stringbuilder>stringbuffer>string
6.什么是內(nèi)部類?內(nèi)部類的作用
答:內(nèi)部類的定義,就是在一個類里面的類,預支對應,包含內(nèi)部類的類稱之為外部類
內(nèi)部類可以分為:成員內(nèi)部類,靜態(tài)內(nèi)部類,方法內(nèi)部類,匿名內(nèi)部類
內(nèi)部類的作用有以下幾點:
1. 內(nèi)部類提供了更好的封裝,可以把內(nèi)部類隱藏在外部類之內(nèi),不允許同一個包中的其他類訪問該類
2. 內(nèi)部類的方法可以直接訪問外部類的所有數(shù)據(jù),包括私有的數(shù)據(jù)
3. 內(nèi)部類所實現(xiàn)的功能使用外部類同樣可以實現(xiàn),只是有時使用內(nèi)部類更方便
注意點:
(1)、內(nèi)部類仍然是一個獨立的類,在編譯之后內(nèi)部類會被編譯成獨立的.class文件,但是前面冠以外部類的類名和$符號。
(2)、內(nèi)部類不能用普通的方式訪問。內(nèi)部類是外部類的一個成員,因此內(nèi)部類可以自由地訪問外部類的成員變量,無論是否是private的。
(3)、內(nèi)部類聲明成靜態(tài)的,就不能隨便的訪問外部類的成員變量,仍然是只能訪問外部類的靜態(tài)成員變量。典型的情況是,內(nèi)部類繼承自某個類或?qū)崿F(xiàn)某個接口,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對象。所以你可以認為內(nèi)部類提供了某種進入其外圍類的窗口。使用內(nèi)部類最吸引人的原因是: 每個內(nèi)部類都能獨立地繼承自一個(接口的)實現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(接口的)實現(xiàn),對于內(nèi)部類都沒有影響。如果沒有內(nèi)部類提供的可以繼承多個具體的或抽象的類的能力,一些設計與編程問題就很難解決。從這個角度看,內(nèi)部類使得多重繼承的解決方案變得完整。接口解決了部分問題,而內(nèi)部類有效地實現(xiàn)了“多重繼承”。
7.抽象類和接口區(qū)別
答:
1.抽象類可以提供成員方法.可以是各種成員變量,可以有靜態(tài)代碼塊和方法,一個類只能繼承一個抽象類
2.接口只能存在public abstract抽象方法,成員變量中必須使用public static final修飾,不可以含有靜態(tài)代碼塊和靜態(tài)方法,一個類可以實現(xiàn)多個接口
8.抽象類的意義,接口的意義
答:抽象類往往用來表示在對問題領域進行分析,設計中得出抽象概念,是對一系列看上去不同,但本質(zhì)相同的具體概念的抽象,即對類的抽象,而接口是對行為的抽象.抽象類是對整個類進行抽象,包括屬性,行為,但是接口卻是對類局部(行為)進行抽象
9.抽象類與接口的應用場景
答:舉個例子,飛機和飛鳥他倆的共性都是飛,那么飛機的類為airplane,飛鳥為bird,那么fly就可以作為一個抽象類,飛機和飛鳥繼承抽象類
例如戰(zhàn)斗機,直升飛機,戰(zhàn)斗機的功能是戰(zhàn)斗,那么戰(zhàn)斗就是一個接口,直升飛機的功能是載人,那么載人就是一個接口,如果出來一個航空戰(zhàn)斗機型號,既要戰(zhàn)斗又要載人,那么就實現(xiàn)兩個接口就好了
10.抽象類是否可以沒有方法和屬性?
答:抽象類可以不含抽象方法

但是含抽象方法的類一定是抽象類
另注:
①java允許類、接口或者成員方法具有抽象屬性,但不允許成員域或構造方法具有抽象屬性
②如果一個類不具有抽象屬性,則不能在該類的類體中定義抽象成員方法
11.泛型中extends和super的區(qū)別
答:請記住PECS原則:生產(chǎn)者(Producer)使用extends,消費者(Consumer)使用super。
生產(chǎn)者使用extends
如果你需要一個列表提供T類型的元素(即你想從列表中讀取T類型的元素),你需要把這個列表聲明成< extends T>,比如List< extends Integer>,因此你不能往該列表中添加任何元素。
消費者使用super
如果需要一個列表使用T類型的元素(即你想把T類型的元素加入到列表中),你需要把這個列表聲明成< super T>,比如List< super Integer>,因此你不能保證從中讀取到的元素的類型。
即是生產(chǎn)者,也是消費者
如果一個列表即要生產(chǎn),又要消費,你不能使用泛型通配符聲明列表,比如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.進程和線程的區(qū)別
:答
進程:具有一定獨立功能的程序關于某個數(shù)據(jù)集合上的一次運行活動,進程是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位.
線程:進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
區(qū)別
進程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產(chǎn)生影響,而線程只是一個進程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進程。
1)?簡而言之,一個程序至少有一個進程,一個進程至少有一個線程.
2)?線程的劃分尺度小于進程,使得多線程程序的并發(fā)性高。
3)?另外,進程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享內(nèi)存,從而極大地提高了程序的運行效率。
4)?線程在執(zhí)行過程中與進程還是有區(qū)別的。每個獨立的線程有一個程序運行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨立執(zhí)行,必須依存在應用程序中,由應用程序提供多個線程執(zhí)行控制。
5)?從邏輯角度來看,多線程的意義在于一個應用程序中,有多個執(zhí)行部分可以同時執(zhí)行。但操作系統(tǒng)并沒有將多個線程看做多個獨立的應用,來實現(xiàn)進程的調(diào)度和管理以及資源分配。這就是進程和線程的重要區(qū)別。
14.final,finally,finalize的區(qū)別
答:
final:修飾符(關鍵字)有三種用法:如果修飾類,不可被繼承,如果修飾變量,不可被修改,如果修飾方法,不可被重寫
finally:通常是房子try..........catch....的后面,構造總是執(zhí)行代碼塊,意味著無論程序正常執(zhí)行還是發(fā)生異常,這里面的代碼只要jvm不關閉都能執(zhí)行,可以將釋放外部資源的代碼卸載finally塊中
finalize:object類中定義的方法,java中允許使用finalize()方法在垃圾收集齊將對象從內(nèi)存中清楚出去之前做必要的清理工作,這個方法是由垃圾收集器在銷毀對象前調(diào)用的,通過重寫finalize()方法可以整理系統(tǒng)資源或者執(zhí)行其他清理工作.
15.序列化的方式,serializable和parcelable的區(qū)別
答:
1.在使用內(nèi)存的時候parcelable類比serializable性能高,所以推薦使用parcelable類
2.serializable在序列化的時候回產(chǎn)生大量的臨時變量,從而引起頻繁的GC
3.parcelable不能使用在要要將數(shù)據(jù)存儲在磁盤上的情況,盡管serializable效率地點,但是這種情況還是適合使用serializable
4.serializable的實現(xiàn),只需要繼承serializable即可,這只是給對象打了一個標記,系統(tǒng)會自動將其序列化
5.parcelable的實現(xiàn),需要在類中添加一個靜態(tài)成員變量CREATOR,這個變量需要繼承Parcelable.Creator
16.靜態(tài)屬性和靜態(tài)方法是否可以被繼承?是否可以被重寫?以及原因?
答:java中靜態(tài)屬性和靜態(tài)方法可以被繼承,但是沒有被重寫(overwrite)而是被隱藏.
原因:
1). 靜態(tài)方法和屬性是屬于類的,調(diào)用的時候直接通過類名.方法名完成對,不需要繼承機制及可以調(diào)用。如果子類里面定義了靜態(tài)方法和屬性,那么這時候父類的靜態(tài)方法或?qū)傩苑Q之為"隱藏"。如果你想要調(diào)用父類的靜態(tài)方法和屬性,直接通過父類名.方法或變量名完成,至于是否繼承一說,子類是有繼承靜態(tài)方法和屬性,但是跟實例方法和屬性不太一樣,存在"隱藏"的這種情況。
2). 多態(tài)之所以能夠?qū)崿F(xiàn)依賴于繼承、接口和重寫、重載(繼承和重寫最為關鍵)。有了繼承和重寫就可以實現(xiàn)父類的引用指向不同子類的對象。重寫的功能是:"重寫"后子類的優(yōu)先級要高于父類的優(yōu)先級,但是“隱藏”是沒有這個優(yōu)先級之分的。
3). 靜態(tài)屬性、靜態(tài)方法和非靜態(tài)的屬性都可以被繼承和隱藏而不能被重寫,因此不能實現(xiàn)多態(tài),不能實現(xiàn)父類的引用可以指向不同子類的對象。非靜態(tài)方法可以被繼承和重寫,因此可以實現(xiàn)多態(tài)。
17.靜態(tài)內(nèi)部類的設計意圖
答:靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類之間存在一個最大的區(qū)別:非靜態(tài)內(nèi)部類在編譯完成之后會隱含地保存著一個引用,該引用是指向創(chuàng)建它的外圍內(nèi),但是靜態(tài)內(nèi)部類卻沒有。
沒有這個引用就意味著:
它的創(chuàng)建是不需要依賴于外圍類的。
它不能使用任何外圍類的非static成員變量和方法。
18.成員內(nèi)部類、靜態(tài)內(nèi)部類、局部內(nèi)部類和匿名內(nèi)部類的理解,以及項目中的應用
答:內(nèi)部類
內(nèi)部類,即定義在一個類的內(nèi)部的類。為什么有內(nèi)部類呢?
我們知道,在java中類是單繼承的,一個類只能繼承另一個具體類或抽象類(可以實現(xiàn)多個接口)。這種設計的目的是因為在多繼承中,當多個父類中有重復的屬性或者方法時,子類的調(diào)用結(jié)果會含糊不清,因此用了單繼承。
而使用內(nèi)部類的原因是:每個內(nèi)部類都能獨立地繼承一個(接口的)實現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(接口的)實現(xiàn),對于內(nèi)部類都沒有影響。
在我們程序設計中有時候會存在一些使用接口很難解決的問題,這個時候我們可以利用內(nèi)部類提供的、可以繼承多個具體的或者抽象的類的能力來解決這些程序設計問題。可以這樣說,接口只是解決了部分問題,而內(nèi)部類使得多重繼承的解決方案變得更加完整。
靜態(tài)內(nèi)部類
說靜態(tài)內(nèi)部類之前,先了解下成員內(nèi)部類(非靜態(tài)的內(nèi)部類)。
成員內(nèi)部類
成員內(nèi)部類也是最普通的內(nèi)部類,它是外圍類的一個成員,所以它可以無限制的訪問外圍類的所有成員屬性和方法,盡管是private的,但是外圍類要訪問內(nèi)部類的成員屬性和方法則需要通過內(nèi)部類實例來訪問。
在成員內(nèi)部類中要注意兩點:
成員內(nèi)部類中不能存在任何static的變量和方法;
成員內(nèi)部類是依附于外圍類的,所以只有先創(chuàng)建了外圍類才能夠創(chuàng)建內(nèi)部類。
靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類之間存在一個最大的區(qū)別:非靜態(tài)內(nèi)部類在編譯完成之后會隱含地保存著一個引用,該引用是指向創(chuàng)建它的外圍內(nèi),但是靜態(tài)內(nèi)部類卻沒有。
沒有這個引用就意味著:
它的創(chuàng)建是不需要依賴于外圍類的。
它不能使用任何外圍類的非static成員變量和方法。
其它兩種內(nèi)部類:局部內(nèi)部類和匿名內(nèi)部類
局部內(nèi)部類
局部內(nèi)部類是嵌套在方法和作用于內(nèi)的,對于這個類的使用主要是應用與解決比較復雜的問題,想創(chuàng)建一個類來輔助我們的解決方案,到那時又不希望這個類是公共可用的,所以就產(chǎn)生了局部內(nèi)部類,局部內(nèi)部類和成員內(nèi)部類一樣被編譯,只是它的作用域發(fā)生了改變,它只能在該方法和屬性中被使用,出了該方法和屬性就會失效。
匿名內(nèi)部類
1、匿名內(nèi)部類是沒有訪問修飾符的。
2、new 匿名內(nèi)部類,這個類首先是要存在的。
3、當所在方法的形參需要被匿名內(nèi)部類使用,那么這個形參就必須為final。
4、匿名內(nèi)部類沒有明面上的構造方法,編譯器會自動生成一個引用外部類的構造方法。
19.談談對kotlin的理解
答:2017年谷歌I/O大會的最后,谷歌宣布將Kotlin語言作為安卓開發(fā)的一級編程語言。Kotlin由JetBrains公司開發(fā),與Java 100%互通,并具備諸多Java尚不支持的新特性。谷歌稱還將與JetBrains公司合作,為Kotlin設立一個非盈利基金會。
Kotlin的文件擴展名為.kt和.kts,使用Kotlin,你可以用更少的代碼獲得更多的功能。 而你寫的代碼越少,你犯的錯誤就越少。除此以外,他還有如下特點:
1> Kotlin編譯為JVM字節(jié)碼或JavaScript,方便在沒有JVM的設備上運行。
2> Kotlin程序可以使用所有現(xiàn)有的Java框架和庫,也就是說所有的現(xiàn)有程序不需要更改就可以直接被調(diào)用。
3> Kotlin可以輕松學習,平易近人。它的規(guī)則及其簡單,語法規(guī)則少,易于學習。
4> Kotlin是開放源碼,沒有收費。雖然java也是開源語言,但是相比于其他的非開源的還是有一定優(yōu)勢的。
5> 將Java自動轉(zhuǎn)換為Kotlin,有強迫癥的也可以這么搞,不用逼死強迫癥的。
6> Kotlin的空安全性很好
7> 空安全 Null Safety- 如上節(jié)所述,Kotlin避免了NullPointerException。
8> 擴展函數(shù)Extension Functions- Kotlin允許我們擴展現(xiàn)有類的功能,而不繼承它們。意味著Kotlin提供了擴展具有新功能的類的能力,而無需繼承類。
20.閉包和局部內(nèi)部類的區(qū)別
答:
閉包就是把函數(shù)以及變量包起來,使得變量的生存周期延長。閉包跟面向?qū)ο笫且豢脴渖系膬蓷l枝,實現(xiàn)的功能是等價的。
局部內(nèi)部類是嵌套在方法和作用于內(nèi)的,對于這個類的使用主要是應用與解決比較復雜的問題,想創(chuàng)建一個類來輔助我們的解決方案,到那時又不希望這個類是公共可用的,所以就產(chǎn)生了局部內(nèi)部類,局部內(nèi)部類和成員內(nèi)部類一樣被編譯,只是它的作用域發(fā)生了改變,它只能在該方法和屬性中被使用,出了該方法和屬性就會失效。
閉包有什么作用:簡而言之,閉包的作用就是在Outer執(zhí)行完并返回后,閉包使得Javascript的垃圾回收機制GC不會收回Outer所占用的資源,因為Outer的內(nèi)部函數(shù)Inner的執(zhí)行需要依賴Outer中的變量。
閉包是一個可調(diào)用的對象,它記錄了一些信息,這些信息來自于創(chuàng)建它的作用域。通過這個定義,可以看出內(nèi)部類是面向?qū)ο蟮拈]包,因為它不僅包含創(chuàng)建內(nèi)部類的作用域的信息,還自動擁有一個指向此外圍類對象的引用,在此作用域內(nèi),內(nèi)部類有權操作所有的成員,包括private成員。
21.string 轉(zhuǎn)換成 integer的方式及原理
答:方式直接是用integer.valueOf(String str)這個方法(注:如果字符串的格式不對,這個方法會拋出NumberFormatException)
原理如下:
在Integer類中的定義如下:
public static Integer valueOf(String s) throws NumberFormatException{
????????return new Integer(parseInt(s, 10));
}
這里因為parseInt方法返回的int型的,這里調(diào)用了一個構造函數(shù)產(chǎn)生了一個新的Integer實例.
這里關心的是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;
????????}
}
很顯然,該方法的第二個參數(shù)表示是基數(shù)(最常用的是十進制,還有十六機制,八進制等等).
如果字符串是空指針,直接拋出異常.
如果基礎小于2或者大于36的話,拋出異常(這種情況一般不會出現(xiàn),因為我們用的最多就是十進制的了).
如果是空字符串,也拋出異常,也就是max=0的情況了.
我們來關注下面的轉(zhuǎn)換過程:
這里使用了Character中的靜態(tài)方法digit,這個方法比較復雜,這里先說明它的功能:對于給定的基數(shù),如果是合法的字符(可以轉(zhuǎn)化為數(shù)字),返回該數(shù)字值,否則返回-1.比如digit('3',10)返回3,digit('a',10)返回-1.
這段程序看起來很簡單,其實還真不容易看懂,這里先說明幾個局部變量的含義吧:
result:記錄返回值
negative:符號標志
i:字符串位置
s:字符串長度
limit:界限
multmin:也是一個界限
digit:當前字符表示的數(shù)字
先看第一個字符是否是'-'號,設定符號標志negative和極限值limit.
注意到limit一定是一個負值.
處理最高位,這里result保存的是負值,這樣就可以對正負數(shù)統(tǒng)一處理.
關鍵就是這個while循環(huán)了,第一個if不用解釋了,肯定是因為非法字符.
第二個if語句的含義:如果result小于multmin,會產(chǎn)生什么結(jié)果呢?
是不是一定會溢出呢?假設不會溢出,就是說結(jié)果必須>=limit.
result小于multmin,result至少應該位multmin-1,后面有result=result*radix=(multmin-1)*radix=multmin*radix-radix
該值肯定小于limit,其中multmin=limit/radix,注意這里都是負數(shù).
所以假設不成里,如果result小于multmin的話,后面一定會溢出.
如果這里沒有判斷的話,溢出就麻煩了,正數(shù)也會變負數(shù)了.
第三個if語句的含義:在這條語句以前肯定沒有溢出,但是有可能加上最后一位digit就溢出了,所以這個判斷也是必要的.
后面的就比較好理解了,else是表示空字符串"".
如果是負數(shù)的還要看是否長度是1,就只是一個'-'號的情況.
如果是正數(shù)的話返回相反數(shù)就可以了.
這里有好多地方都有可能拋出異常,只要看明白了程序就知道這個異常是那條語句拋出的了,這里考慮溢出異常:異常1和異常2.
Ingeter.Max_VALUE=2147483647
下面的兩條語句在不同的地方拋出異常.
Ingeter.valueOf("2147483648");這個在異常2拋出的.
Ingeter.valueOf("21474836471");這個在異常1拋出的.
這里簡單的分析了String轉(zhuǎn)化為Ingeter的過程,其實整個Ingeter類也就主要是這個方法了,Byte和Short都是調(diào)用這個方法的.
看看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;
}
了解這個方法后就再也不會為Integer.valueOf()產(chǎn)生的異常感到意外了,特別是在JSP中,因為參數(shù)都是String型的,轉(zhuǎn)換的時候動不動就出現(xiàn)異
常,你該知道怎么回事了吧.
內(nèi)容摘自:https://blog.csdn.net/treeroot/article/details/92923