1. Java的安全性
- 使用引用取代了指針,指針的功能強大烈和,但是也容易造成錯誤招刹,如數(shù)組越界問題窝趣。
- 擁有一套異常處理機制哑舒,使用關(guān)鍵字 throw洗鸵、throws膘滨、try、catch丹弱、finally
- 不用程序員顯示控制內(nèi)存釋放蹈矮,JVM 有垃圾回收機制
- 強制類型轉(zhuǎn)換需要符合一定規(guī)則
- 字節(jié)碼傳輸使用了加密機制
- 運行環(huán)境提供保障機制:字節(jié)碼校驗器->類裝載器->運行時內(nèi)存布局->文件訪問限制
2. Java三大特性
- 封裝
- 封裝指的是屬性私有化泛鸟,根據(jù)需要提供setter和getter方法來訪問屬性北滥。即隱藏具體屬性和實現(xiàn)細節(jié)再芋,僅對外開放接口,控制程序中屬性的訪問級別济赎。
- 封裝目的:增強安全性和簡化編程司训,使用者不必在意具體實現(xiàn)細節(jié)壳猜,而只是通過外部接口即可訪問類的成員统扳。
- 繼承
- 繼承是指將多個相同的屬性和方法提取出來咒钟,新建一個父類。Java中一個類只能繼承一個父類溉知,且只能繼承訪問權(quán)限非private的屬性和方法。 子類可以重寫父類中的方法帚湘,命名與父類中同名的屬性大诸。
- 繼承目的:代碼復用资柔。
- 多態(tài)
- 多態(tài)可以分為兩種:設計時多態(tài)和運行時多態(tài)贿堰。
- 設計時多態(tài):即重載羹与,是指Java允許方法名相同而參數(shù)不同(返回值可以相同也可以不相同)纵搁。
- 運行時多態(tài):即重寫,是指Java運行根據(jù)調(diào)用該方法的類型決定調(diào)用哪個方法徘层。要求方法名趣效、參數(shù)和返回值必須相同英支。
- 多態(tài)目的:增加代碼的靈活度干花。
3. 多態(tài)程序綁定
- 定義:綁定指的是一個方法的調(diào)用與方法所在的類或?qū)ο?方法主體)關(guān)聯(lián)起來池凄。對java來說肿仑,綁定分為靜態(tài)綁定和動態(tài)綁定
- 靜態(tài)綁定(前期綁定):在程序執(zhí)行前方法已經(jīng)被綁定尤慰,此時由編譯器或其它連接程序?qū)崿F(xiàn)雷蹂。在編譯階段匪煌,綁定的是類信息,即為定義的類的類型齿拂。針對java簡單的可以理解為程序編譯期的綁定署海;這里特別說明一點叹侄,java當中的方法趾代,只有final撒强,static飘哨,private芽隆,重載方法(overloaded methods)和構(gòu)造方法是靜態(tài)綁定胚吁。所有的變量都是靜態(tài)綁定腕扶。
- 動態(tài)綁定(后期綁定):在運行時根據(jù)具體對象的類型進行綁定吨掌。發(fā)生在運行階段膜宋,綁定的是對象信息秋茫。重寫方法(overridden methods)使用的是動態(tài)綁定
- 動態(tài)綁定的過程:
1)虛擬機提取對象實際類型的方法表学辱;
2)虛擬機搜索方法簽名策泣;
3)調(diào)用方法萨咕。
4. Java四種引用類型
- 強引用:Java中默認聲明的就是強引用危队,只要強引用存在茫陆,垃圾回收器將永遠不會回收被引用的對象簿盅,哪怕內(nèi)存不足時桨醋,JVM也會直接拋出OutOfMemoryError喜最,不會去回收瞬内。如果想中斷強引用與對象之間的聯(lián)系遂鹊,可以顯示的將強引用賦值為null秉扑,這樣一來舟陆,JVM就可以適時的回收對象了
- 軟引用:軟引用是用來描述一些非必需但仍有用的對象秦躯。在內(nèi)存足夠的時候踱承,軟引用對象不會被回收,只有在內(nèi)存不足時琢唾,系統(tǒng)則會回收軟引用對象采桃,如果回收了軟引用對象之后仍然沒有足夠的內(nèi)存普办,才會拋出內(nèi)存溢出異常衔蹲。這種特性常常被用來實現(xiàn)緩存技術(shù)踪危,比如網(wǎng)頁緩存贞远,圖片緩存等蓝仲。
- 弱引用:弱引用的引用強度比軟引用要更弱一些袱结,無論內(nèi)存是否足夠垢夹,只要 JVM 開始進行垃圾回收果元,那些被弱引用關(guān)聯(lián)的對象都會被回收而晒。(GC時發(fā)生)
- 虛引用:虛引用是最弱的一種引用關(guān)系倡怎,如果一個對象僅持有虛引用监署,那么它就和沒有任何引用一樣血公,它隨時可能會被回收,主要用來跟蹤對象被垃圾回收的活動够滑。
5. 不可變對象
- 不可變對象:對象在創(chuàng)建完成后彰触,不能再改變它的狀態(tài)况毅。即不能改變對象內(nèi)的成員變量尔许,包括基本數(shù)據(jù)類型的值不能改變味廊,引用類型的變量不能指向其他的對象余佛,引用類型指向的對象的狀態(tài)也不能改變辉巡。
- 不可變對象有什么好處郊楣?
1)不可變對象可以提高String Pool(字符串常量池)的效率和安全性痢甘。如果你知道一個對象是不可變動塞栅,那么需要拷貝的對象的內(nèi)容時就不用復制它本身而只是復制它的地址放椰,復制地址(通常一個指針的大小)需要很小的內(nèi)存砾医,效率也很好如蚜。二是對于其他引用同一個對象的其他變量也不會造成影響错邦。
2)不可變對象對于多線程是安全的撬呢,因為在多線程同時進行的情況下魂拦,一個可變對象的值很可能被其他線程改變芯勘,這樣會造成不可預期的結(jié)果荷愕,而使用不可變對象就可以避免這種情況出現(xiàn)狈癞。
6. String
- String是否可變蝶桶?
? ? Java中String類就是對字符數(shù)組的封裝真竖。Jdk8中String類有兩個成員變量char value[]和int hash厌小,value是private final的恢共,hash被private修飾,也就是說在String類內(nèi)部璧亚,一旦初始化就不能被改變讨韭。所以可以認為String對象是不可變的。 - String為什么要設計為不可變?
java將String設成不可變最大的原因是效率和安全透硝。
1)字符串常量池的需要,只有字符串不可變時濒生,字符串常量池才能實現(xiàn)埋泵。
2)多線程安全
3)字符串不變性保證了hash碼的唯一性,因此可以放心的進行緩存罪治,這也是一種性能優(yōu)化手段丽声,意味著不必每次都重新計算新的哈希碼,使得字符串很適合作為 Map的鍵
4)類加載器要用到字符串觉义,不可變提供了安全性恒序,以便類被正確地加載。
5)String被許多的Java類(庫)用來當做參數(shù)谁撼,例如網(wǎng)絡連接地址URL,文件路徑path滋饲,還有反射機制所需要的String參數(shù)等厉碟, 假若String不是固定不變的,將會引起各種安全隱患屠缭。 - String對象真的不可變嗎箍鼓?
用反射,可以反射出String對象中的value屬性呵曹, 進而改變通過獲得的value引用改變數(shù)組的結(jié)構(gòu)款咖。可以通過類對象的getDeclaredField()方法字段(Field)對象奄喂,然后再通過字段對象的setAccessible(true)將其設置為可以訪問铐殃,接下來就可以通過get/set方法來獲取/設置字段的值了。
7. Java創(chuàng)建對象的4種方式
- 使用new關(guān)鍵字:new關(guān)鍵字直接在堆內(nèi)存上創(chuàng)建對象跨新。
- 反射:使用Class類的newInstance方法可以調(diào)用無參的構(gòu)造器來創(chuàng)建對象富腊,如果是有參構(gòu)造器,則需要使用Class的forName方法和Constructor來進行對象的創(chuàng)建域帐。
- 使用Clone方法:調(diào)用一個對象的clone方法赘被,JVM就會創(chuàng)建一個新的對象,將前面的對象的內(nèi)容全部拷貝進去肖揣,用clone方法創(chuàng)建對象并不會調(diào)用任何構(gòu)造函數(shù)民假。
- 反序列化:一個對象實現(xiàn)了Serializable接口,就可以把對象寫入到文件中龙优,并通過讀取文件來創(chuàng)建對象羊异。
8. 反射
? ? JAVA語言編譯之后會生成一個.class文件,反射就是通過字節(jié)碼文件找到某一個類、類中的方法以及屬性等球化。反射機制指的是程序在運行時能夠獲取自身的信息秽晚。在JAVA中,只要給定類的名字筒愚,那么就可以通過反射機制來獲取類的所有信息赴蝇。Java 的動態(tài)就體現(xiàn)在反射。通過反射我們可以實現(xiàn)動態(tài)裝配巢掺,降低代碼的耦合度句伶;動態(tài)代理等。反射的過度使用會嚴重消耗系統(tǒng)資源陆淀。
? ? 反射的實現(xiàn)主要借助以下四個類:Class:類的對象考余,Constructor:類的構(gòu)造方法,F(xiàn)ield:類中的屬性對象轧苫,Method:類中的方法對象楚堤。
- 反射的作用:
1)可以使用反射動態(tài)地創(chuàng)建類型的實例,將類型綁定到現(xiàn)有對象含懊,或從現(xiàn)有對象中獲取類型
2)應用程序需要在運行時從某個特定的程序集中載入一個特定的類型身冬,以便實現(xiàn)某個任務時可以用到反射。
3)反射主要應用于類庫岔乔,這些類庫需要知道一個類型的定義酥筝,以便提供更多的功能。
9. StringBuffer和StringBuilder
- 相同點:StringBuffer 和 StringBuilder 類的對象能夠被多次的修改雏门,并且不產(chǎn)生新的未使用對象嘿歌。底層實現(xiàn)上的話,StringBuffer其實就是比StringBuilder多了Synchronized修飾符茁影。
- 區(qū)別:
1)StringBuilder 的方法不是線程安全的(不能同步訪問)
2)StringBuilder 相較于 StringBuffer 有速度優(yōu)勢宙帝,所以多數(shù)情況下建議使用 StringBuilder 類募闲。 - 小結(jié):
1)如果要操作少量的數(shù)據(jù)用 String;
2)多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) StringBuffer沪编;
3)單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) StringBuilder。
10. java.lang.Object的常用方法
- getClass() 獲取類結(jié)構(gòu)信息
- toString() 把對象轉(zhuǎn)變成字符串
- hashCode() 獲取哈希碼
- equals(Object) 默認比較對象的地址值是否相等年扩,子類可以重寫比較規(guī)則
- notify() 多線程中喚醒功能
- notifyAll() 多線程中喚醒所有等待線程的功能
- wait()讓持有對象鎖的線程進入等待
- wait(long timeout)讓持有對象鎖的線程進入等待,設置超時毫秒數(shù)時間
- wait(long timeout相嵌, int nanos)讓持有對象鎖的線程進入等待腿时,設置超時納秒數(shù)時間
11. 為什么Java把wait與notify放在Object中?
- 功能角度
1)wait與notify的原始目的饭宾,是多線程場景下看铆,某條件觸發(fā)另一邏輯,該條件對應的直接關(guān)系為某種對象否淤,進而對應為Object棠隐,其對應為內(nèi)存資源。
2)Thread對應為CPU啰扛,與具體條件不是直接關(guān)系嗡贺,Thread是對象的執(zhí)行依附者暑刃。 - 內(nèi)存角度
1)線程的同步需要Monitor的管理膜眠,其與實際操作系統(tǒng)的重型資源(鎖)相關(guān)宵膨。
2)只有涉及多線程的場景,才需要線程同步谷扣,如果wait與notify放在Thread,則每個Thread都需要分配Monitor会涎,浪費資源末秃。
3)如果放在Object籽御,單線程場景不分配Monitor,只在多線程分配铃将。分配Monitor的方法為檢測threadId的不同劲阎。
12. 裝箱和拆箱
? ? 裝箱是通過調(diào)用包裝器類的 valueOf 方法實現(xiàn)的;拆箱是通過調(diào)用包裝器類的 xxxValue 方法實現(xiàn)的奥此,xxx代表對應的基本數(shù)據(jù)類型稚虎。如int裝箱的時候自動調(diào)用Integer的valueOf(int)方法偎捎;Integer拆箱的時候自動調(diào)用Integer的intValue方法茴她。包含算術(shù)運算會觸發(fā)自動拆箱。存在大量自動裝箱的過程祭钉,如果裝箱返回的包裝對象不是從緩存中獲取慌核,會創(chuàng)建很多新的對象申尼,比較消耗內(nèi)存师幕。
- 整型的包裝類 valueOf 方法返回對象時霹粥,在常用的取值范圍內(nèi),會返回緩存對象宗侦。
- 浮點型的包裝類 valueOf 方法返回新的對象忆蚀。
- 布爾型的包裝類 valueOf 方法 Boolean類的靜態(tài)常量 TRUE | FALSE。
13. Integer和String的比較操作
- 使用 == 比較:
- 基本類型 - 基本類型舶斧、基本類型 - 包裝對象返回 true
- 包裝對象 - 包裝對象察皇,非同一個對象(對象的內(nèi)存地址不同)返回 false什荣;對象的內(nèi)存地址相同返回 true,如值等于 100 的兩個 Integer 對象(原因是 JVM 緩存部分基本類型常用的包裝類對象嗜闻,如 Integer -128 ~ 127 是被緩存的)
- 使用 equals() 比較
- 包裝對象-基本類型返回 true
- 包裝對象-包裝對象返回 true
Integer a = 1琉雳;
Integer b = 1翠肘;
Integer c = 128辫秧;
Integer d = 128盟戏;
// [-128,127]范圍的自動裝箱(box)喂急,同值是同一個對象
System.out.println(a == b); // true
// 不在[-128探入,127]范圍裝箱的Integer懂诗,值相同也不是同一個對象
System.out.println(c == d)殃恒; // false
// 使用new一個對象的方法
Integer a = new Integer(1)辱揭;
Integer b = new Integer(1)问窃;
System.out.println(a == b)域庇; // false
System.out.println(a.equals(b))覆积; // true
System.out.println(a.equals(1))宽档; // true
System.out.println(a == 1)雌贱; // true, Integer和int用==比較馋没,Integer自動拆箱unbox篷朵,轉(zhuǎn)換為普通int間的比較
/**
* String的比較婆排,==是引用比較段只,比較字符串是否相同用equals
*/
//用引號創(chuàng)建一個字符串的時候赞枕,首先會去常量池中尋找有沒有相等的常量對象,沒有的話就在常量池中創(chuàng)建這個常量對象姐赡;有的話就直接返回這個常量對象的引用
String str1 = "haha"柠掂;
String str2 = "haha"涯贞;
String str3 = new String("haha");
String str4 = new String("haha")姥饰;
// true孝治,首先 String str1 = "hello"谈飒,會先到常量池中檢查是否有“hello”的存在杭措,發(fā)現(xiàn)是沒有的,于是在常量池中創(chuàng)建“hello”對象鸳址,并將常量池中的引用賦值給str1稿黍;第二個字面量 String str2 = "hello"巡球,在常量池中檢測到該對象了邓嘹,直接將引用賦值給str2汹押。
System.out.println(str1 == str2)棚贾;
// false, 每個String對象都是不同的陈辱,所以引用指向的堆地址肯定也不同,所以false震贵。
System.out.println(str3 == str4);
// false媚送,因為==比較的是引用的地址塘偎,s2指的是常量池中常量對象的地址吟秩,而s1指的是堆中String對象的地址绽淘,肯定不同沪铭。
System.out.println(str1 == str3)杀怠;
// true赔退,因為jdk重寫了equals()方法,比較的是字符串的內(nèi)容票编。
System.out.println(str1.equals(str2))慧域;
//true昔榴, JDK 1.7后碘橘,intern方法還是會先去查詢常量池中是否有已經(jīng)存在痘拆,如果存在,則返回常量池中的引用规揪,這一點與之前沒有區(qū)別温峭,區(qū)別在于凤藏,如果在常量池找不到對應的字符串揖庄,則不會再將字符串拷貝到常量池抠艾,而只是在常量池中生成一個對原字符串的引用检号。
System.out.println(str3.intern()==str1);
14. 動態(tài)鏈接庫和靜態(tài)鏈接庫
- 靜態(tài)鏈接庫:當要使用時翘盖,連接器會找出程序所需的函數(shù)馍驯,然后將它們拷貝到執(zhí)行文件汰瘫,由于這種拷貝是完整的混弥,所以一旦連接成功蝗拿,靜態(tài)程序庫也就不再需要了蒿涎。
- 動態(tài)鏈接庫:某個程序在運行中要調(diào)用某個動態(tài)鏈接庫函數(shù)的時候劳秋,操作系統(tǒng)首先會查看所有正在運行的程序,看在內(nèi)存里是否已有此庫函數(shù)的拷貝了。如果有辛慰,則讓其共享那一個拷貝帅腌;只有沒有才鏈接載入麻汰。在程序運行的時候五鲫,被調(diào)用的動態(tài)鏈接庫函數(shù)被安置在內(nèi)存的某個地方位喂,所有調(diào)用它的程序?qū)⒅赶蜻@個代碼段塑崖。因此规婆,這些代碼必須使用相對地址,而不是絕對地址掘鄙。在編譯的時候通铲,我們需要告訴編譯器颅夺,這些對象文件是用來做動態(tài)鏈接庫的吧黄,所以要用地址無關(guān)代碼(Position Independent Code (PIC))拗慨。動態(tài)鏈接庫的加載方式有兩種:隱式加載和顯示加載赵抢。
15. 正則表達式
- 定義:在編寫處理字符串的程序時,經(jīng)常會有查找符合某些復雜規(guī)則的字符串的需要宠叼。正則表達式就是用于描述這些規(guī)則的工具冒冬。換句話說简烤,正則表達式就是記錄文本規(guī)則的代碼横侦。
- Java中的String類提供了支持正則表達式操作的方法丈咐,包括:matches()棵逊、replaceAll()辆影、replaceFirst()蛙讥、split()次慢。
16. Java基本數(shù)據(jù)類型及其包裝類
Java 為每個原始類型提供了包裝類型:
- 原始類型:boolean迫像,char闻妓,byte由缆,short均唉,int,long罩缴,float靴庆,double
- 包裝類型:Boolean音榜,Character拿诸,Byte亩码,Short描沟,Integer,Long泞遗,F(xiàn)loat史辙,Double
17. 值傳遞和引用傳遞
一般認為聊倔,java內(nèi)的傳遞都是值傳遞
- 值傳遞是對基本型變量而言的,傳遞的是該變量的一個副本纵潦,改變副本不影響原變量邀层。
- 引用傳遞一般是對于對象型變量而言的,傳遞的是該對象地址的一個副本寥院, 并不是原對象本身劲赠。所以對引用對象進行操作會同時改變原對象。
18. 深拷貝和淺拷貝
- 淺拷貝:復制基本類型的屬性秸谢、引用類型的屬性凛澎、棧中的變量和變量指向堆內(nèi)存中的對象的指針,不復制堆內(nèi)存中的對象估蹄。
- 深拷貝:復制基本類型的屬性塑煎、引用類型的屬性臭蚁、棧中的變量和變量指向堆內(nèi)存中的對象的指針和堆內(nèi)存中的對象最铁。
19. 為什么會出現(xiàn)4.0-3.6=0.40000001這種現(xiàn)象?
? ? 2進制的小數(shù)無法精確的表達10進制小數(shù)垮兑,計算機在計算10進制小數(shù)的過程中要先轉(zhuǎn)換為2進制進行計算冷尉,這個過程中出現(xiàn)了誤差。
20. 十進制的數(shù)在內(nèi)存中是怎么存的系枪?
補碼的形式
- 正數(shù)的原反補一樣
- 負數(shù)的反碼是將原碼除了符號位的其余位取反雀哨,補碼是給反碼加1.
21. Lamda表達式
- 定義:Lambda 表達式(lambda expression)是一個匿名函數(shù),Lambda 規(guī)定接口中只能有一個需要被實現(xiàn)的方法私爷,不是規(guī)定接口中只能有一個方法
- 思想:函數(shù)式編程思想
- 優(yōu)點:1. 簡潔雾棺。2. 非常容易并行計算。
- 缺點:1. 若不用并行計算当犯,很多時候計算速度沒有比傳統(tǒng)的 for 循環(huán)快垢村。(并行計算有時需要預熱才顯示出效率優(yōu)勢)2. 不容易調(diào)試。
22. Java 8系列之Stream
? ? Stream 是用函數(shù)式編程方式在集合類上進行復雜操作的工具嚎卫,其集成了Java 8中的眾多新特性之一的聚合操作嘉栓,開發(fā)者可以更容易地使用Lambda表達式,并且更方便地實現(xiàn)對集合的查找拓诸、遍歷侵佃、過濾以及常見計算等。
- Stream的操作分類奠支,在一次聚合操作中馋辈,可以有多個Intermediate,但是有且只有一個Terminal倍谜。Intermediate主要是用來對Stream做出相應轉(zhuǎn)換及限制流迈螟,實際上是將源Stream轉(zhuǎn)換為一個新的Stream叉抡,以達到需求效果。
- Intermediate:map (mapToInt答毫, flatMap 等)褥民、 filter、 distinct洗搂、 sorted消返、 peek、 skip耘拇、 parallel撵颊、 sequential、 unordered
- Terminal:forEach惫叛、 forEachOrdered倡勇、 toArray、 reduce挣棕、 collect译隘、 min亲桥、 max洛心、 count、iterator
- Short-circuiting:anyMatch题篷、 allMatch词身、 noneMatch、 findFirst番枚、 findAny法严、 limit
23. final關(guān)鍵字
- 使用final的原因:第一個原因是把方法鎖定,以防任何繼承類修改它的含義葫笼;第二個原因是效率深啤。
- 作用:
1)當用final修飾一個類時,表明這個類不能被繼承路星。final類中的所有成員方法都會被隱式地指定為final方法溯街。
2)對于一個final變量,如果是基本數(shù)據(jù)類型的變量洋丐,則其數(shù)值一旦在初始化之后便不能更改呈昔;
3)如果是引用類型的變量,則在對其初始化之后便不能再讓其指向另一個對象友绝。
24. final/finally/finalize
- final 用于聲明屬性堤尾,方法和類,分別表示屬性不可變迁客,方法不可覆蓋郭宝,類不可繼承辞槐。
- finally是異常處理語句結(jié)構(gòu)的一部分,表示總是執(zhí)行粘室。
- finalize是Object類的一個方法催蝗,在垃圾收集器執(zhí)行的時候會調(diào)用被回收對象的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收育特,例如關(guān)閉文件等丙号。
25. Java中的IO流
java.io包中還有許多其他的流,主要是為了提高性能和使用方便缰冤。
- 按照流向劃分為輸入流和輸出流
- 按照操作單元分劃分為字節(jié)流和字符流
- 字節(jié)流:InputStream犬缨、OutputStream
- 字符流:InputStreamReader、OutputStreamWriter
- 按照流的角色劃分為節(jié)點流和處理流
26. 既然有了字節(jié)流棉浸,為什么還要有字符流?
? ? 字符流是由 Java 虛擬機將字節(jié)轉(zhuǎn)換得到的怀薛,這個過程非常耗時,并且迷郑,如果我們不知道編碼類型就很容易出現(xiàn)亂碼問題枝恋。所以, I/O 流提供了一個直接操作字符的接口嗡害,方便我們平時對字符進行流操作焚碌。如果音頻文件、圖片等媒體文件用字節(jié)流比較好霸妹,如果涉及到字符的話使用字符流比較好十电。
27. java序列化
- 定義:序列化是將 Java 對象轉(zhuǎn)換成字節(jié)流的過程。反序列化是將字節(jié)流轉(zhuǎn)換成 Java 對象的過程叹螟。
- 作用:當Java對象需要在網(wǎng)絡上傳輸或者持久化存儲到文件時鹃骂,就需要對Java對象進行序列化處理。
- 實現(xiàn):類實現(xiàn) Serializable 接口罢绽,這個接口沒有需要實現(xiàn)的方法畏线。實現(xiàn) Serializable 接口是為了告訴 jvm 這個類的對象可以被序列化。
28. Java 序列化中如果有些字段不想進行序列化良价,怎么辦寝殴?
對于不想進行序列化的變量,使用 transient 關(guān)鍵字修飾棚壁。transient 關(guān)鍵字的作用是:阻止實例中那些用此關(guān)鍵字修飾的的變量序列化杯矩;當對象被反序列化時,被 transient 修飾的變量值不會被持久化和恢復袖外。transient 只能修飾變量史隆,不能修飾類和方法。
29. 泛型
- 定義:泛型曼验,即“參數(shù)化類型”泌射。將類型作為參數(shù)傳入方法中粘姜,如List<String>。
- 優(yōu)點:在編譯的時候檢查類型安全熔酷,并且所有的強制轉(zhuǎn)換都是自動和隱式的孤紧,提高代碼的重用率。
- Java泛型的實現(xiàn)方法:類型擦除
Java的泛型是偽泛型拒秘,因為Java在編譯期間号显,所有的泛型信息都會被擦掉。Java的泛型基本上都是在編譯器這個層次上實現(xiàn)的躺酒,在生成的字節(jié)碼中是不包含泛型中的類型信息的押蚤,使用泛型的時候加上類型參數(shù),在編譯器編譯的時候會去掉羹应,這個過程稱為類型擦除揽碘。
30. 抽象類和接口
- 聲明方法的存在而不去實現(xiàn)它的類被叫做抽象類(abstract class),它用于要創(chuàng)建一個體現(xiàn)某些基本行為的類园匹,并為該類聲明方法雳刺,但不能在該類中實現(xiàn)該類的情況。不能創(chuàng)建abstract 類的實例裸违。然而可以創(chuàng)建一個變量掖桦,其類型是一個抽象類,并讓它指向具體子類的一個實例累颂。不能有抽象構(gòu)造函數(shù)或抽象靜態(tài)方法滞详。Abstract 類的子類為它們父類中的所有抽象方法提供實現(xiàn)凛俱,否則它們也是抽象類紊馏。取而代之,在子類中實現(xiàn)該方法蒲犬。知道其行為的其它類可以在類中實現(xiàn)這些方法朱监。
- 接口(interface)是抽象類的變體。在接口中原叮,所有方法都是抽象的赫编。多繼承性可通過實現(xiàn)這樣的接口而獲得。接口中的所有方法都是抽象的奋隶,沒有一個有程序體擂送。接口只可以定義static final成員變量。接口的實現(xiàn)與子類相似唯欣,除了該實現(xiàn)類不能從接口定義中繼承行為嘹吨。當類實現(xiàn)特殊接口時,它定義(即將程序體給予)所有這種接口的方法境氢。然后蟀拷,它可以在實現(xiàn)了該接口的類的任何對象上調(diào)用接口的方法碰纬。由于有抽象類,它允許使用接口名作為引用變量的類型问芬。通常的動態(tài)聯(lián)編將生效悦析。引用可以轉(zhuǎn)換到接口類型或從接口類型轉(zhuǎn)換,instanceof 運算符可以用來決定某對象的類是否實現(xiàn)了接口此衅。
- 區(qū)別:
1)接口中所有的方法隱含的都是抽象的强戴。而抽象類則可以同時包含抽象和非抽象的方法。
2)類可以實現(xiàn)很多個接口挡鞍,但是只能繼承一個抽象類
3)Java接口中聲明的變量默認都是final的酌泰。抽象類可以包含非final的變量。
4)Java接口中的成員函數(shù)默認是public的匕累。抽象類的成員函數(shù)可以是private陵刹,protected或者是public。
5)抽象類可以在不提供接口方法實現(xiàn)的情況下實現(xiàn)接口欢嘿。
6)類可以不實現(xiàn)抽象類和接口聲明的所有方法衰琐,當然,在這種情況下炼蹦,類也必須得聲明成是抽象的羡宙。
7)接口是絕對抽象的,不可以被實例化掐隐。抽象類也不可以被實例化狗热,但是,如果它包含main方法的話是可以被調(diào)用的虑省。
31. java類的里面可以再定義一個類嗎
? ? java類里面還可以定義一個類匿刮,即內(nèi)部類。java內(nèi)部類分為: 成員內(nèi)部類探颈、方法(局部)內(nèi)部類熟丸、靜態(tài)內(nèi)部類、匿名內(nèi)部類 伪节。
- 成員內(nèi)部類:
- 成員內(nèi)部類可以無條件訪問外部類的屬性和方法光羞,但是外部類想要訪問內(nèi)部類屬性或方法時,必須要創(chuàng)建一個內(nèi)部類對象怀大,然后通過該對象訪問內(nèi)部類的屬性或方法
- 局部內(nèi)部類
- 局部內(nèi)部類存在于方法中纱兑。
- 他和成員內(nèi)部類的區(qū)別在于局部內(nèi)部類的訪問權(quán)限僅限于方法或作用域內(nèi)。
- 靜態(tài)內(nèi)部類:
- 靜態(tài)內(nèi)部類和成員內(nèi)部類相比多了一個static修飾符化借。只能訪問外部類的靜態(tài)成員變量與靜態(tài)方法潜慎。
- 靜態(tài)內(nèi)部類的非靜態(tài)成員可訪問外部類的靜態(tài)變量,而不可訪問外部類的非靜態(tài)變量。
- 匿名內(nèi)部類:
- 沒有類名勘纯,沒有class關(guān)鍵字也沒有extends和implements等關(guān)鍵字修飾局服。唯一沒有構(gòu)造方法的內(nèi)部類。
- 類的定義和對象的實例化同時進行驳遵。
- 內(nèi)部類的好處
- 完善了Java多繼承機制淫奔,由于每一個內(nèi)部類都可以獨立的繼承接口或類,所以無論外部類是否繼承或?qū)崿F(xiàn)了某個類或接口堤结,對于內(nèi)部類沒有影響唆迁。
- 方便寫事件驅(qū)動程序。
32. &和&&竞穷、|和||
- &:邏輯與唐责,& 兩邊的表達式都會進行運算
- &&:短路與,&& 左邊的表達式結(jié)果為 false 時瘾带,&& 右邊的表達式不參與計算
- |:邏輯或鼠哥,| 兩邊的表達式都會進行運算
- ||:短路或,|| 左邊的表達式結(jié)果為 true 時看政,|| 右邊的表達式不參與計算
33. 不使用任何中間變量朴恳,交換a,b兩個數(shù)字的值
- a=a+b允蚣;b=a-b于颖;a=a-b;(a+b可能越界)
- a = a ^ b嚷兔;b = a ^ b森渐;a = a ^ b;
34. 常見異常
常見異常類及其父子關(guān)系:
Throwable
| ├ Error
| │ ├ IOError
| │ ├ LinkageError
| │ ├ ReflectionError
| │ ├ ThreadDeath
| │ └ VirtualMachineError
| │
| ├ Exception
| │ ├ CloneNotSupportedException
| │ ├ DataFormatException
| │ ├ InterruptedException
| │ ├ IOException
| │ ├ ReflectiveOperationException
| │ ├ RuntimeException(不需要代碼顯式捕獲處理)
| │ ├ ArithmeticException
| │ ├ ClassCastException
| │ ├ ConcurrentModificationException
| │ ├ IllegalArgumentException
| │ ├ IndexOutOfBoundsException
| │ ├ NoSuchElementException
| │ ├ NullPointerException
| │ └ SecurityException
| │ └ SQLException
運行時異常都是 RuntimeException 子類異常
- NullPointerException - 空指針異常
- ClassCastException - 類轉(zhuǎn)換異常
- IndexOutOfBoundsException - 下標越界異常
- ArithmeticException - 計算異常
- IllegalArgumentException - 非法參數(shù)異常
- NumberFormatException - 數(shù)字格式異常
- UnsupportedOperationException 操作不支持異常
- ArrayStoreException - 數(shù)據(jù)存儲異常冒晰,操作數(shù)組時類型不一致
- BufferOverflowException - IO 操作時出現(xiàn)的緩沖區(qū)上溢異常
- NoSuchElementException - 元素不存在異常
- InputMismatchException - 輸入類型不匹配異常
- ConcurrentModificationException – 并發(fā)修改異常
35. 設計模式
總體來說設計模式分為三大類(25種):
- 創(chuàng)建型模式同衣,共五種:工廠方法模式、抽象工廠模式翩剪、單例模式乳怎、建造者模式、原型模式前弯。
- 結(jié)構(gòu)型模式,共七種:適配器模式秫逝、裝飾器模式恕出、代理模式、外觀模式违帆、橋接模式浙巫、組合模式、享元模式。
- 行為型模式的畴,共十一種:策略模式、模板方法模式丧裁、觀察者模式护桦、迭代子模式、責任鏈模式煎娇、命令模式二庵、備忘錄模式、狀態(tài)模式缓呛、訪問者模式催享、中介者模式、解釋器模式哟绊。
- 其實還有兩類:并發(fā)型模式和線程池模式因妙。
36. 設計模式的六大原則
總原則:開閉原則,開閉原則就是說對擴展開放票髓,對修改關(guān)閉兰迫。
- 單一職責原則:每個類應該實現(xiàn)單一的職責,如若不然炬称,就應該把類拆分汁果。
- 里氏替換原則:任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)玲躯。
- 依賴倒轉(zhuǎn)原則:面向接口編程据德,依賴于抽象而不依賴于具體。
- 接口隔離原則:每個接口中不存在子類用不到卻必須實現(xiàn)的方法跷车,如果不然棘利,就要將接口拆分。使用多個隔離的接口朽缴,比使用單個接口(多個接口方法集合到一個的接口)要好善玫。
- 最少知道原則:一個類對自己依賴的類知道的越少越好。
- 合成復用原則:盡量首先使用合成/聚合的方式密强,而不是使用繼承茅郎。
37. 單例模式
- 定義:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點或渤。
- 作用:解決一個全局使用的類頻繁地創(chuàng)建與銷毀系冗。
- 主要優(yōu)點:
- 提供了對唯一實例的受控訪問。
- 由于在系統(tǒng)內(nèi)存中只存在一個對象薪鹦,因此可以節(jié)約系統(tǒng)資源掌敬,對于一些需要頻繁創(chuàng)建和銷毀的對象單例模式無疑可以提高系統(tǒng)的性能惯豆。
- 允許可變數(shù)目的實例。
- 主要缺點:
- 由于單利模式中沒有抽象層奔害,因此單例類的擴展有很大的困難楷兽。
- 單例類的職責過重,在一定程度上違背了“單一職責原則”华临。
- 濫用單例將帶來一些負面問題芯杀,如為了節(jié)省資源將數(shù)據(jù)庫連接池對象設計為的單例類,可能會導致共享連接池對象的程序過多而出現(xiàn)連接池溢出银舱;如果實例化的對象長時間不被利用瘪匿,系統(tǒng)會認為是垃圾而被回收,這將導致對象狀態(tài)的丟失寻馏。
- 分類:
1)餓漢式(線程安全):在調(diào)用getInstance()方法前就初始化instance實例- 優(yōu)點:沒有加鎖棋弥,執(zhí)行效率會提高。
- 缺點:類加載時就初始化诚欠,浪費內(nèi)存顽染。
public class Singleton {
//在類的內(nèi)部創(chuàng)建一個類的實例,且為static
private static Singleton instance = new Singleton()轰绵;
//私有化構(gòu)造器
private Singleton (){}
//此公共方法只能通過類來調(diào)用粉寞,因為設置的是static
public static Singleton getInstance() {
return instance;
}
}
2)懶漢式(線程不安全):調(diào)用getInstance()方法時才創(chuàng)建instance實例
public class Singleton {
private static Singleton instance左腔;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton()唧垦;
}
return instance;
}
}
解決方法:
a) 加Synchorized鎖
public class Singleton {
private static Singleton instance液样;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton()振亮;
}
return instance;
}
}
b) 雙端檢鎖(加鎖前后都進行判斷)
public class Singleton {
private volatile static Singleton singleton鞭莽;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton()坊秸;
}
}
}
return singleton;
}
}
c) 靜態(tài)內(nèi)部類
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton()澎怒;
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE褒搔;
}
}
d) 枚舉是實現(xiàn)單例模式的最佳方法。它更簡潔喷面,自動支持序列化機制星瘾,絕對防止多次實例化。
public enum Singleton {
INSTANCE乖酬;
public void whateverMethod() {
}
}
38. 生產(chǎn)者消費者模式
? ? 生產(chǎn)者消費者問題是線程模型中的經(jīng)典問題:生產(chǎn)者和消費者在同一時間段內(nèi)共用同一存儲空間死相,生產(chǎn)者向空間里生產(chǎn)數(shù)據(jù),而消費者取走數(shù)據(jù)咬像。優(yōu)點:支持并發(fā)、解耦。