針對(duì)JAVA基礎(chǔ)以及常問知識(shí)點(diǎn)的總結(jié)
以下為問題目錄
java中==和equals和hashCode的區(qū)別
String、StringBuffer、StringBuilder、StringTokenizer區(qū)別
int、char、long各占多少字節(jié)數(shù)
int與integer的區(qū)別
談?wù)剬?duì)java多態(tài)的理解
什么是內(nèi)部類??jī)?nèi)部類的作用
抽象類和接口區(qū)別
抽象類的意義
抽象類與接口的應(yīng)用場(chǎng)景
抽象類是否可以沒有方法和屬性?
泛型中extends和super的區(qū)別
父類的靜態(tài)方法能否被子類重寫
進(jìn)程和線程的區(qū)別
final,finally,finalize的區(qū)別
序列化的方式
Serializable 和Parcelable 的區(qū)別
靜態(tài)內(nèi)部類的設(shè)計(jì)意圖
閉包和局部?jī)?nèi)部類的區(qū)別
string 轉(zhuǎn)換成 integer的方式及原理
一、java中==和equals和hashCode的區(qū)別
==用于比較兩個(gè)變量數(shù)值,或?qū)?yīng)內(nèi)存地址是否相等。
equals是Object類中提供的方法,其方法中直接使用==比較兩對(duì)象,都是比較的引用,故對(duì)基本數(shù)據(jù)類型,與==相同。想要進(jìn)行內(nèi)容的比較的話可以進(jìn)行方法重寫。比如String類:
String s1 = new String("Hello");
String s1 = new String("Hello");
new了兩個(gè)對(duì)象,對(duì)于==來說肯定是false的,對(duì)于equals來說,因?yàn)閮?nèi)容相同,所以返回true。
hashCode()也是Object類里面的方法,返回值是一個(gè)對(duì)象的哈希碼(int值),如果沒有重寫hashCode()方法,任何對(duì)象的hashCode()方法都是不同的。用戶一般調(diào)用的是equals,hashCode就比較少。在hashmap中,key是不可以重復(fù)的,這里的判斷是否重復(fù)用了equals和hashCode,因此對(duì)于“不可重復(fù)”,兩者只要一個(gè)不同即可。
因此,equals和hashCode的關(guān)系:
1、如果兩個(gè)對(duì)象equals,Java運(yùn)行時(shí)環(huán)境會(huì)認(rèn)為他們的hashcode一定相等。
2、如果兩個(gè)對(duì)象不equals,他們的hashcode有可能相等。
3、如果兩個(gè)對(duì)象hashcode相等,他們不一定equals。
4、如果兩個(gè)對(duì)象hashcode不相等,他們一定不equals。
另外,hashCode的返回是int型,比較起來不直觀
問:覆蓋equals方法時(shí)要注意什么?
答:同時(shí)也要覆蓋hashCode方法,根據(jù)上面規(guī)則,否則會(huì)違反Object.hashCode的通用規(guī)定,從而導(dǎo)致該類無法與所有基于散列值的集合類(hashmap、hashset、hashtable)結(jié)合在一起正常運(yùn)行。
二、String、StringBuffer、StringBuilder和StringTokenizer的區(qū)別
① String是final修飾的不可變類,對(duì)象一旦創(chuàng)建,其值不可改變,我們平時(shí)用String修改字符串其實(shí)是新建了對(duì)象,改變堆內(nèi)存地址的指向。這樣會(huì)產(chǎn)生很多無用對(duì)象,需要被垃圾回收器回收,因此影響性能。(浪費(fèi)空間,影響性能)。而StringBuffer、StringBuilder是可變類。

②StringBuffer在初始化時(shí),只能使用構(gòu)造函數(shù)(StringBuffer s = new StringBuffer(“abc”);)的方式賦值。而String初始化可以用構(gòu)造函數(shù),也可以直接賦值(String s="abc";)
③StringBuffer和StringBuilder區(qū)別 : StringBuffer是線程安全的,而StringBuilder非線程安全,但是其執(zhí)行效率更高。
④StringTokenizer是用來分隔字符串的工具類。
問1:String字符串修改原理?
答1:首先新建StringBuffer,其次調(diào)用append方法,最后調(diào)用toString將結(jié)果返回
問2:因此三者使用場(chǎng)景?
答2:(1)如果要操作少量的數(shù)據(jù)用 String;
(2)多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) StringBuffer;
(3)單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) StringBuilder。
三、int、char、long各占多少字節(jié)數(shù)
byte是存儲(chǔ)空間的基本計(jì)量單位。1byte 存1個(gè)英文字母,2個(gè)byte存一個(gè)漢字。規(guī)定上是1個(gè)字節(jié)等于8位(1Byte = 8bit)。

四、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
拓展:
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變量實(shí)際上是對(duì)一個(gè)Integer對(duì)象的引用,所以兩個(gè)通過new生成的Integer變量永遠(yuǎn)是不相等的(因?yàn)閚ew生成的是兩個(gè)對(duì)象,其內(nèi)存地址不同)。
非new生成的Integer變量(Integer i =10;)和new Integer()生成的變量比較時(shí),結(jié)果為false。(因?yàn)榉莕ew生成的Integer變量指向的是java常量池中的對(duì)象,而new Integer()生成的變量指向堆中新建的對(duì)象,兩者在內(nèi)存中的地址不同)
對(duì)于兩個(gè)非new生成的Integer對(duì)象,進(jìn)行比較時(shí),如果兩個(gè)變量的值在區(qū)間-128到127之間,則比較結(jié)果為true,如果兩個(gè)變量的值不在此區(qū)間,則比較結(jié)果為false.(java在編譯Integer i = 100 ;時(shí),會(huì)翻譯成為Integer i = Integer.valueOf(100);)
public static Integer valueOf(int i){
? ? assert IntegerCache.high >= 127;
? ? if (i >= IntegerCache.low && i <= IntegerCache.high){
? ? ? ? return IntegerCache.cache[i + (-IntegerCache.low)];
? ? }
? ? return new 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了.
因此對(duì)于在-128到127之間的integer,它們可以用"=="來比較,在范圍之外的可以用"equal"來比較
五、談?wù)剬?duì)java多態(tài)的理解
多態(tài)分為兩種
a. 編譯時(shí)多態(tài):方法的重載;
b. 運(yùn)行時(shí)多態(tài):JAVA運(yùn)行時(shí)系統(tǒng)根據(jù)調(diào)用該方法的實(shí)例的類型來決定選擇調(diào)用哪個(gè)方法則被稱為運(yùn)行時(shí)多態(tài)。(我們平時(shí)說得多的事運(yùn)行時(shí)多態(tài),所以多態(tài)主要也是指運(yùn)行時(shí)多態(tài));
上述描述認(rèn)為重載也是多態(tài)的一種表現(xiàn),不過多態(tài)主要指運(yùn)行時(shí)多態(tài)
運(yùn)行時(shí)多態(tài)
a. 面向?qū)ο蟮娜筇匦裕悍庋b、繼承、多態(tài)。從一定角度來看,封裝和繼承幾乎都是為多態(tài)而準(zhǔn)備的。這是我們最后一個(gè)概念,也是最重要的知識(shí)點(diǎn)。
b. 多態(tài)的定義:指允許不同類的對(duì)象對(duì)同一消息做出響應(yīng)。即同一消息可以根據(jù)發(fā)送對(duì)象的不同而采用多種不同的行為方式。(發(fā)送消息就是函數(shù)調(diào)用)
c. 實(shí)現(xiàn)多態(tài)的技術(shù)稱為:動(dòng)態(tài)綁定(dynamic binding),是指在執(zhí)行期間判斷所引用對(duì)象的實(shí)際類型,根據(jù)其實(shí)際的類型調(diào)用其相應(yīng)的方法。
d. 多態(tài)的作用:消除類型之間的耦合關(guān)系。
多態(tài)存在的三個(gè)必要條件
一、要有繼承;
二、要有重寫;
三、父類引用指向子類對(duì)象。
實(shí)現(xiàn)機(jī)制(變現(xiàn)形式):重載(水平)和覆蓋(垂直)
六、什么是內(nèi)部類??jī)?nèi)部類的作用
①什么是內(nèi)部類:
將一個(gè)類定義在另一個(gè)類里面或者一個(gè)方法里面,這樣的類稱為內(nèi)部類。
②內(nèi)部類的分類:
1、靜態(tài)內(nèi)部類
指被聲明為static的內(nèi)部類,他可以不依賴內(nèi)部類而實(shí)例,而通常的內(nèi)部類需要實(shí)例化外部類,從而實(shí)例化。靜態(tài)內(nèi)部類不可以有與外部類有相同的類名。不能訪問外部類的普通成員變量,但是可以訪問靜態(tài)成員變量和靜態(tài)方法(包括私有類型)
2、成員內(nèi)部類
成員內(nèi)部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態(tài)成員)。
當(dāng)成員內(nèi)部類擁有和外部類同名的成員變量或者方法時(shí),會(huì)發(fā)生隱藏現(xiàn)象,即默認(rèn)情況下訪問的是成員內(nèi)部類的成員。
一個(gè) 靜態(tài)內(nèi)部類去掉static 就是成員內(nèi)部類,他可以自由的引用外部類的屬性和方法,無論是靜態(tài)還是非靜態(tài)。但是不可以有靜態(tài)屬性和方法、
3、局部?jī)?nèi)部類
局部?jī)?nèi)部類是定義在一個(gè)方法或者一個(gè)作用域里面的類,它和成員內(nèi)部類的區(qū)別在于局部?jī)?nèi)部類的訪問僅限于方法內(nèi)或者該作用域內(nèi)。
4、匿名內(nèi)部類
匿名內(nèi)部類就是沒有名字的內(nèi)部類,不使用關(guān)鍵字class、extends、implement關(guān)鍵字,無構(gòu)造函數(shù),需要繼承其他類或?qū)崿F(xiàn)其他接口。
③作用
1.每個(gè)內(nèi)部類都能獨(dú)立的繼承一個(gè)接口的實(shí)現(xiàn),所以無論外部類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒有影響。內(nèi)部類使得多繼承的解決方案變得完整,
2.方便將存在一定邏輯關(guān)系的類組織在一起,又可以對(duì)外界隱藏。
3.可以避免修改接口而實(shí)現(xiàn)同一個(gè)類中兩種同名方法的調(diào)用。(繼承和實(shí)現(xiàn)的類和借口中有同名方法)
4.代碼更簡(jiǎn)潔、緊湊,但是可讀性可能會(huì)下降。
七、抽象類和接口異同
相同點(diǎn):
1.都含有抽象方法,不能被實(shí)例化
2.接口的實(shí)現(xiàn)類或者抽象類的子類都只有在實(shí)現(xiàn)了方法后才能被實(shí)例化
不同:
1.接口與類的區(qū)別:接口需要實(shí)現(xiàn)(通過implement),抽象類只能繼承(extend用s)。一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,但是只能繼承一個(gè)類,通過接口可以間接達(dá)到多重繼承的目的
2.接口只有定義,其方法不能直接在接口中實(shí)現(xiàn)。但是接口類可以。
3.接口強(qiáng)調(diào)特定功能的實(shí)現(xiàn),設(shè)計(jì)理念為“has - a”關(guān)系,抽象類強(qiáng)調(diào)從屬關(guān)系,為“is -a”關(guān)系。
4.接口中定義的成員變量默認(rèn)為public static final? ,必須賦初值。其成員方法都是public、abstract修飾的。? 抽象類中可以有自己的數(shù)據(jù)成員變量,也可以有非抽象方法。抽樣類中成員變量默認(rèn)為default(本包可見)。
因此,如果功能需要累加,用抽象類;不需要累加則用接口。
八、抽象類的定義
1,為子類提供一個(gè)公共的類型;
2,封裝子類中重復(fù)內(nèi)容(成員變量和方法);
3,定義有抽象方法,子類雖然有不同的實(shí)現(xiàn),但該方法的定義是一致的。
九、抽象類與接口的應(yīng)用場(chǎng)景
抽象類多用于在同類事物中有無法具體描述的方法的場(chǎng)景,所以當(dāng)子父類之間有邏輯上的層次關(guān)系時(shí),推薦使用抽象類;
接口多用于不同類之間,定義不同類之間的通信規(guī)則,所以當(dāng)希望支持差別較大的兩個(gè)或更多對(duì)象之間的特定交互活動(dòng)時(shí),應(yīng)該使用接口。
接口(interface)的應(yīng)用場(chǎng)合:
類與類之前需要特定的接口進(jìn)行協(xié)調(diào),而不在乎其如何實(shí)現(xiàn)。
作為能夠?qū)崿F(xiàn)特定功能的標(biāo)識(shí)存在,也可以是什么接口方法都沒有的純粹標(biāo)識(shí)。
需要將一組類視為單一的類,而調(diào)用者只通過接口來與這組類發(fā)生聯(lián)系。
需要實(shí)現(xiàn)特定的多項(xiàng)功能,而這些功能之間可能完全沒有任何聯(lián)系。
抽象類(abstract class)的應(yīng)用場(chǎng)合:
一句話,在既需要統(tǒng)一的接口,又需要實(shí)例變量或缺省的方法的情況下,就可以使用它。最常見的有:
定義了一組接口,但又不想強(qiáng)迫每個(gè)實(shí)現(xiàn)類都必須實(shí)現(xiàn)所有的接口??梢杂胊bstract class定義一組方法體,甚至可以是空方法體,然后由子類選擇自己所感興趣的方法來覆蓋。
某些場(chǎng)合下,只靠純粹的接口不能滿足類與類之間的協(xié)調(diào),還必需類中表示狀態(tài)的變量來區(qū)別不同的關(guān)系。abstract的中介作用可以很好地滿足這一點(diǎn)。
規(guī)范了一組相互協(xié)調(diào)的方法,其中一些方法是共同的,與狀態(tài)無關(guān)的,可以共享的,無需子類分別實(shí)現(xiàn);而另一些方法卻需要各個(gè)子類根據(jù)自己特定的狀態(tài)來實(shí)現(xiàn)特定的功能
十、抽象類是否可以沒有方法和屬性?
抽象類中可以沒有抽象方法,但有抽象方法的一定是抽象類。所以,java中 抽象類里面可以沒有抽象方法。比如HttpServlet類。抽象類和普通類的區(qū)別就在于,抽象類不能被實(shí)例化,就是不能被new出來,即使抽象類里面沒有抽象方法。
? 抽象類的作用在于子類對(duì)其的繼承和實(shí)現(xiàn),也就是多態(tài);而沒有抽象方法的抽象類的存在價(jià)值在于:實(shí)例化了沒有意義,因?yàn)轭愐呀?jīng)定義好了,不能改變其中的方法體,但是實(shí)例化出來的對(duì)象卻滿足不了要求,只有繼承并重寫了他的子類才能滿足要求。所以才把它定義為沒有抽象方法的抽象類
十一、泛型中extends和super的區(qū)別
上界通配符extends:泛型中extends的主要作用是設(shè)定類型通配符的上限。只能用于方法返回,告訴編譯器此返參的類型的最小繼承邊界為T,T和T的父類都能接收,但是入?yún)㈩愋蜔o法確定,只能接受null的傳入
下界通配符super:泛型中super的主要作用是設(shè)定類型通配符的下限。只能用于限定方法入?yún)?,告訴編譯器入?yún)⒅荒苁荰或其子類型,而返參只能用Object類接收
<? super T>表示包括T在內(nèi)的任何T的父類,<? extends T>表示包括T在內(nèi)的任何T的子類
拓展:PECS
請(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<Integer>。
十二、父類的靜態(tài)方法能否被子類重寫
不能,父類的靜態(tài)方法能夠被子類繼承,但是不能夠被子類重寫,即使子類中的靜態(tài)方法與父類中的靜態(tài)方法完全一樣,也是兩個(gè)完全不同的方法。
十三、進(jìn)程和線程的區(qū)別
進(jìn)程是資源分配的最小單位,線程是程序執(zhí)行(運(yùn)算調(diào)度)的最小單位。
進(jìn)程有自己的獨(dú)立地址空間,每啟動(dòng)一個(gè)進(jìn)程,系統(tǒng)就會(huì)為它分配地址空間,建立數(shù)據(jù)表來維護(hù)代碼段、堆棧段和數(shù)據(jù)段,這種操作非常昂貴。而線程是共享進(jìn)程中的數(shù)據(jù)的,使用相同的地址空間,因此CPU切換一個(gè)線程的花費(fèi)遠(yuǎn)比進(jìn)程要小很多,同時(shí)創(chuàng)建一個(gè)線程的開銷也比進(jìn)程要小很多。
線程之間的通信更方便,同一進(jìn)程下的線程共享全局變量、靜態(tài)變量等數(shù)據(jù),而進(jìn)程之間的通信需要以通信的方式(IPC)進(jìn)行。不過如何處理好同步與互斥是編寫多線程程序的難點(diǎn)。
但是多進(jìn)程程序更健壯,多線程程序只要有一個(gè)線程死掉,整個(gè)進(jìn)程也死掉了,而一個(gè)進(jìn)程死掉并不會(huì)對(duì)另外一個(gè)進(jìn)程造成影響,因?yàn)檫M(jìn)程有自己獨(dú)立的地址空間。
十四、final,finally,finalize的區(qū)別
final用于聲明屬性方法和類,①對(duì)于final屬性,該變量不可變,而且是引用的不可變,不關(guān)心指向?qū)ο髢?nèi)容的變化。必須初始化。②final方法,不允許任何子類重寫該方法。③final類,不能被繼承,所有方法不能被重寫。
finally:作為異常處理的一部分,只用于try/catch語句中,并且附帶一個(gè)語句塊,代表這段語句最終一定會(huì)被執(zhí)行,經(jīng)常被用在需要釋放資源的情況下。
finaliza是Object的一個(gè)方法,在垃圾回收器執(zhí)行時(shí)會(huì)調(diào)用回收對(duì)象的finalize()方法,可以覆蓋此方法來實(shí)現(xiàn)對(duì)其他資源的回收,例如關(guān)閉文件。(一旦準(zhǔn)備好釋放對(duì)象占有的空間,會(huì)首先調(diào)用finalize方法,并在下一次垃圾回收動(dòng)作發(fā)生時(shí),才會(huì)真正回收對(duì)象占用的內(nèi)存)
十五、序列化的方式
兩種對(duì)象持久化方式:序列化和內(nèi)外部序列化。
(1)序列化
a 含義:在分布式系統(tǒng)中,在進(jìn)行遠(yuǎn)程通信過程中,無論是任何數(shù)據(jù)類型,都是以二進(jìn)制序列形式在網(wǎng)絡(luò)上傳送。序列化就是一種將對(duì)象以一連串的字節(jié)描述的過程,用于解決在對(duì)對(duì)象流進(jìn)行讀寫操作時(shí)的問題。
b 實(shí)現(xiàn)序列化:類要實(shí)現(xiàn)Serializable接口。使用一個(gè)輸出流構(gòu)造一個(gè)對(duì)象流對(duì)象,緊接著,使用該對(duì)象的writeObject(Object obj)方法就可以將obj對(duì)象寫出(保存其狀態(tài)),要恢復(fù)時(shí)刻使用其對(duì)應(yīng)輸出流。
c 序列化的特點(diǎn):
如果一個(gè)類能被序列化,其子類也可以
static代表類的成員,transient代表對(duì)象的臨時(shí)數(shù)據(jù),因此被聲明為這兩種類型的數(shù)據(jù)成員是不能被序列化的
d 使用場(chǎng)景:
使用序列化會(huì)影響系統(tǒng)的性能,若非必須盡量不用。以下情況需要使用:
需要用網(wǎng)絡(luò)來發(fā)送對(duì)象,或?qū)ο蟮臓顟B(tài)需要被持久化倒數(shù)據(jù)庫(kù)或文件中
序列化可以實(shí)現(xiàn)深復(fù)制,即可以復(fù)制引用的對(duì)象
(2)外部序列化
外部序列化與序列化的區(qū)別是序列化是內(nèi)置的API,只需要實(shí)現(xiàn)Serilizable接口即可。而外部序列化,Externalizable接口中的讀寫方法必須由開發(fā)人員實(shí)現(xiàn),因此編寫難度更大,但是更靈活,可能會(huì)提高性能。
拓展:
問:在用Serializable接口實(shí)現(xiàn)序列化時(shí),類中所有屬性都會(huì)被實(shí)例化,那么怎么實(shí)現(xiàn)部分屬性序列化??
答:一、實(shí)現(xiàn)Externnalizable接口,可用readExternal和 writeExternal來控制序列化和反序列化的屬性? ? 二、使用transient關(guān)鍵字指定不被序列化的屬性。
十六、Serializable 和Parcelable 的區(qū)別
Serializable 是Java序列化技術(shù),其方式簡(jiǎn)單,只要類實(shí)現(xiàn)下該接口,然后增加一個(gè)唯一個(gè)序列化id: private static final long serialVersionUID = 1L; 默認(rèn)方式最好直接設(shè)置為1L,因?yàn)閖ava? sdk會(huì)自動(dòng)進(jìn)行hash計(jì)算,并生成唯一的UID值。
Parcelable是android特有的序列化API,它的出現(xiàn)是為了解決Serializable在序列化的過程中消耗資源嚴(yán)重的問題,但是因?yàn)楸旧硎褂眯枰謩?dòng)處理序列化和反序列化過程,會(huì)與具體的代碼綁定,使用較為繁瑣,一般只獲取內(nèi)存數(shù)據(jù)的時(shí)候使用。
? ? ? ? 1.在使用內(nèi)存的時(shí)候Parcelable比Serializable的性能高。
? ? ? ? 2.Serializable在序列化的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量,從而引起頻繁的GC(內(nèi)存回收)。
? ? ? ? 3.Parcelable不能使用在將對(duì)象存儲(chǔ)在磁盤上這種情況,因?yàn)樵谕饨绲淖兓翽arcelable不能很好的保證數(shù)據(jù)的持續(xù)性。