1.JDK1.8新特性?
提供lambda表示式極大地減少了程式碼的冗餘; 在介面中可以使用default和static關鍵字來修飾介面中的普通方法; 提供新的API LocalDate | LocalTime | LocalDateTime (1)Java.util.Date和SimpleDateFormatter執行緒上都不安全,而LocalDate和LocalTime和 String一樣都是不可改變類,執行緒上比較安全,還不能修改; (2)Java.util.Date月份從0開始,12月是11,而java.time.LocalDate月份和星期都改成了 enum, 就不可能出錯了;
2.物件導向和麵向過程的區別?
程式導向
優點:效能比物件導向高,因為類呼叫時需要例項化,開銷比較大,比較消耗資源。比如,微控制器、嵌入式開發、Linux/Unix 等一般採用程式導向開發,效能是最重要的因素。
缺點:沒有物件導向易維護、易複用、易擴充套件。
物件導向
優點:易維護、易複用、易擴充套件,由於物件導向有封裝、繼承、多型性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易於維護。
缺點:效能比程式導向低。
3.什麼是值傳遞和引用傳遞?
值傳遞,是對基本型變數而言的,傳遞的是該變數的一個副本,改變副本不影響原變數。
引用傳遞,一般是對於物件型變數而言的,傳遞的是該物件地址的一個副本,並不是原物件本身。
一般認為,Java 內的傳遞都是值傳遞,Java 中例項物件的傳遞是引用傳遞。
4.什麼是不可變物件
不可變物件指物件一旦被建立,狀態就不能再改變。任何修改都會建立一個新的物件,如 String、Integer及其它包裝類。
5.講講類的例項化順序?
初始化順序如下:
父類靜態變數
父類靜態程式碼塊
子類靜態變數、
子類靜態程式碼塊
父類非靜態變數(父類例項成員變數)
父類建構函式
子類非靜態變數(子類例項成員變數)
子類建構函式
6.java 建立物件的幾種方式
採用new
通過反射
採用clone
通過序列化機制
前2者都需要顯式地呼叫構造方法。造成耦合性最高的恰好是第一種,因此你發現無論什麼框架,只要涉及到解耦必先減少new的使用
7.Java訪問修飾符的作用域
作用域 當前類 同包 子類 其它
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N
8.switch中能否使用string作為引數?
在jdk1.7之前,switch只能支援byte,short,char,int或者其他對應的封裝類以及Enum型別.jdk1.7之後開始支援String
9.switch中能否作用在byte,long上?
可以用在byte上,不能用在long上
10.什麼是自動拆裝箱?
自動裝箱和拆箱,就是基本型別和引用型別之間的轉換。
把基本資料型別轉換成包裝類的過程就是打包裝,為裝箱。
把包裝類轉換成基本資料型別的過程就是拆包裝,為拆箱。
13.如何正確的退出多層巢狀迴圈?
使用標號和break;
繼承
1.Java支援多繼承麼?
Java類中不支援多繼承,但是可以多實現,所以介面的擴充套件性比較好,實際開發中儘量避免繼承的使用
2.父類的靜態方法能否被子類重寫**
不能。重寫只適用於例項方法,不能用於靜態方法,而子類當中含有和父類相同簽名的靜態方法,我們一般稱之為隱藏。
3.繼承的好處和壞處
好處:1、子類能自動繼承父類的物件 2、建立子類的物件時,無須建立父類的物件 壞處:1、破壞封裝,子類與父類之間緊密耦合,子類依賴於父類的實現,子類缺乏獨立性。 2、支援擴充套件,但是往往以增強系統結構的複雜度為代價 3、不支援動態繼承。在執行時,子類無法選擇不同的父類 4、子類不能改變父類的介面
介面抽象類
1.介面的意義
規範,擴充套件,回撥。
2.抽象類的意義
為其他子類提供一個公共的型別
封裝子類中重複定義的內容
定義抽象方法,子類雖然有不同的實現,但是定義時一致的
3.抽 象 的 (abstract) 方 法 是 否 可 同 時 是 靜 態 的 (static), 是 否 可 同 時 是 本 地 方 法(native)
abstract關鍵字不能同時與static或private或final同時修飾一個方法;
4.抽象類和介面區別?
-
語法區別:
-
抽象類可以有構造方法,介面不能有構造方法
-
抽象類中可以有普通成員變數,介面中沒有普通成員變數;
-
抽象類中可以有非抽象的方法,介面中的方法都必須是抽象的;
-
抽象類中的方法可以是public,protected型別,介面中的方法只能是public型別的,切 預設為public abstract型別;
-
抽象類中可以有靜態方法,介面中不能有靜態方法;
-
抽象類中的靜態變數訪問型別可以是任意的,但介面中的靜態變數只能是public static final 型別。
-
-
-
應用區別:
-
介面更多是在系統架構方面發揮作用,主要用於定義模組之間的通訊契約;而抽象類在程式碼方法 發揮作用,可以使用程式碼塊的重用;
-
5.Java中介面可不可以繼承一般類,為什麼?
不可以因為介面中只能出現3種成員:
-
公共的靜態常量
-
公共的抽象方法
-
靜態內部類
而一個類中,就算什麼都不寫,也必須帶一個構造方法,在extends時就會被子類繼承,如果是介面也會 繼承這個構造方法,很明顯構造方法不在上面三項之列 而如果類中有一般的方法和成員變數,也會被子類全部繼承,這些更不能出現在介面中了,所以介面是絕 對不可能繼承一個類的
6.過載與重寫區別
override(重寫)
1、方法名、引數、返回值相同。
2、子類方法不能縮小父類方法的訪問許可權。
3、子類方法不能丟擲比父類方法更多的異常(但子類方法可以不丟擲異常)。
4、存在於父類和子類之間。
5、被final修飾的方法,不能被重寫。
overload(過載)
1、引數型別、個數、順序至少有一個不相同。
2、不能過載只有返回值不同的方法名。
3、存在於父類和子類、同類中。
7.final有哪些用法?
1.被final修飾的類不可以被繼承
2.被final修飾的方法不可以被重寫
3.被final修飾的變數不可以被改變。如果修飾引用,那麼表示引用不可變,引用指向的內容可變。
注:修飾變數, final 資料型別 變數名=資料值; 如果該變數是基本資料型別,則值不能修改,如果該變數是引用資料型別,則地址值不能改(既只能new一次);
4.被final修飾的方法,JVM會嘗試將其內聯,以提高執行效率
5.被final修飾的常量,在編譯階段會存入常量池中。
回答出編譯器對final域要遵守的兩個重排序規則更好:
1.在建構函式內對一個final域的寫入,與隨後把這個被構造物件的引用賦值給一個引用變數,這兩個操作之間不能重排序。
2.初次讀一個包含final域的物件的引用,與隨後初次讀這個final域,這兩個操作之間不能重排序。
多型
1.多型的好處和弊端
許不同類物件對同一訊息做出響應,即同一訊息可以根據傳送物件的不同而採用多種不同的行為方式(傳送訊息就是函式呼叫)。即父型別的引用指向子型別的物件。
主要有以下優點:
可替換性:多型對已存在程式碼具有可替換性
可擴充性:增加新的子類不影響已經存在的類結構
更加靈活
弊端:
不能使用子類的特有內容
2.程式碼中如何實現多型
實現多型主要有以下三種方式:
-
介面實現
-
繼承父類重寫方法
-
同一類中進行方法過載
3.Java 中實現多型的機制是什麼?
父類物件指向子類引用
內部類Lambda
1.內部類的作用?
內部類可以有多個例項,每個例項都有自己的狀態資訊,並且與其他外圍物件的資訊相互獨立.在單個外圍類當中,可以讓多個內部類以不同的方式實現同一介面,或者繼承同一個類.建立內部類物件的時刻不依賴於外部類物件的建立。
內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問。
2.一個java檔案內部可以有類?(非內部類)
只能有一個public公共類,但是可以有多個default修飾的類。
3.Lambda的使用前提是什麼?
當需要一個介面的實現類物件,且介面中有且僅有一個抽象方法的時候,可以使用lambda完成這個實現類要做的事情;(替代匿名內部類)
4.Lambda與匿名內部類區別
lambda表示式編譯後並不會生成.class檔案,而匿名內部類編譯後會產生單獨的class檔案;
匿名內部類可以用在類,抽象類,介面中,而lambda表示式只能用在有且僅有一個抽象方法的介面中;
static關鍵字
1.是否可以在static環境中訪問非static變數?
static變數在Java中是屬於類的,它在所有的例項中的值是一樣的。當類被Java虛擬機器載入的時候,會對static變數進行初始化。如果你的程式碼嘗試不用例項來訪問非static的變數,編譯器會報錯,因為這些變數還沒有被建立出來,還沒有跟任何例項關聯上。
2.static都有哪些用法?
被static所修飾的變數/方法都屬於類的靜態資源,類例項所共享。
static也用於靜態塊,多用於初始化操作:
此外static也多用於修飾內部類,此時稱之為靜態內部類。
3.靜態變數和例項變數的區別?
靜態變數儲存在方法區,屬於類所有。例項變數儲存在堆當中,其引用存在當前執行緒棧。
4.static特點
如果修飾構造程式碼塊,僅在類第一次載入的時候,執行一次;
如果修飾成員變數,這個變數的值屬於類;可以被所有的物件共享;
如果修飾成員方法,在方法中不能使用this,super;
靜態的內容優先於物件存在!
資料型別
1.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4請問s5==s2返回什麼?
返回false。在編譯過程中,編譯器會將s2直接優化為”ab”,會將其放置在常量池當中,s5則是被建立在堆區,相當於s5=new String(“ab”);
2.3*0.1==0.3返回值是什麼
false,因為有些浮點數不能完全精確的表示出來
3.基本資料型別的預設值?基本資料型別所佔的位元組以及封裝他們的類?
-
預設值
-
byte、short、int、long的預設值為0
-
float、double預設值為0.0
-
char預設值為空
-
boolean預設值為false
-
-
所佔位元組
-
byte 1個位元組--Byte
-
short 2個位元組--Short
-
char 2個位元組--Character
-
int 4個位元組--Integer
-
long 8個位元組--Long
-
float 4個位元組--Float
-
double 8個位元組--Double
-
4.String屬於那個類,以及常用的方法?
-
.java.lang.string
-
substring(),indexOf(),concat(),endswith(),length(),replace()
5.String, StringBuffer和StringBuilder區別
String的值是不可改變的,這就導致每次對String的操作都會生成新的String物件,不禁效率底下, 而且浪費大量的記憶體空間;
StringBuilder是可變類,任何對他指向的字串的操作都不會產生新的對 象,但單執行緒不安全;
StringBuffer底層方法使用了synchronized關鍵字,執行緒比較安全,但效率 較StringBuilder慢
異常相關
1.error和exception有什麼區別
error表示系統級的錯誤,是java執行環境內部錯誤或者硬體問題,不能指望程式來處理這樣的問題,除了退出執行外別無選擇,它是Java虛擬機器丟擲的。
exception 表示程式需要捕捉、需要處理的異常,是由與程式設計的不完善而出現的問題,程式必須處理的問題
2.執行時異常和一般異常有何不同
Java提供了兩類主要的異常:runtimeException和checkedException
一般異常(checkedException)主要是指IO異常、SQL異常等。對於這種異常,JVM要求我們必須對其進行cathc處理,所以,面對這種異常,不管我們是否願意,都是要寫一大堆的catch塊去處理可能出現的異常。
執行時異常(runtimeException)我們一般不處理,當出現這類異常的時候程式會由虛擬機器接管。比如,我們從來沒有去處理過NullPointerException,而且這個異常還是最常見的異常之一。
出現執行時異常的時候,程式會將異常一直向上拋,一直拋到遇到處理程式碼,如果沒有catch塊進行處理,到了最上層,如果是多執行緒就有Thread.run()丟擲,如果不是多執行緒那麼就由main.run()丟擲。丟擲之後,如果是執行緒,那麼該執行緒也就終止了,如果是主程式,那麼該程式也就終止了。
其實執行時異常的也是繼承自Exception,也可以用catch塊對其處理,只是我們一般不處理罷了,也就是說,如果不對執行時異常進行catch處理,那麼結果不是執行緒退出就是主程式終止。
如果不想終止,那麼我們就必須捕獲所有可能出現的執行時異常。如果程式中出現了異常資料,但是它不影響下面的程式執行,那麼我們就該在catch塊裡面將異常資料捨棄,然後記錄日誌。如果,它影響到了下面的程式執行,那麼還是程式退出比較好些。
3.Java中異常處理機制的原理
Java通過物件導向的方式對異常進行處理,Java把異常按照不同的型別進行分類,並提供了良好的介面。當一個方法出現異常後就會丟擲一個異常物件,該物件中包含有異常資訊,呼叫這個物件的方法可以捕獲到這個異常並對異常進行處理。Java的異常處理是通過5個關鍵詞來實現的:try catch throw throws finally。
一般情況下是用try來執行一段程式,如果出現異常,系統會丟擲(throws),我們可以通過它的型別來捕捉它,或最後由預設處理器來處理它(finally)。
try:用來指定一塊預防所有異常的程式
catch:緊跟在try後面,用來捕獲異常
throw:用來明確的丟擲一個異常
throws:用來標明一個成員函式可能丟擲的各種異常
finally:確保一段程式碼無論發生什麼異常都會被執行的一段程式碼。
4.你平時在專案中是怎樣對異常進行處理的。
1)儘量避免出現runtimeException 。例如對於可能出現空指標的程式碼,帶使用物件之前一定要判斷一下該物件是否為空,必要的時候對runtimeException
也進行try catch處理。
(2)進行try catch處理的時候要在catch程式碼塊中對異常資訊進行記錄,通過呼叫異常類的相關方法獲取到異常的相關資訊,返回到web端,不僅要給使用者良好的使用者體驗,也要能幫助程式設計師良好的定位異常出現的位置及原因。例如,以前做的一個專案,程式遇到異常頁面會顯示一個圖片告訴使用者哪些操作導致程式出現了什麼異常,同時圖片上有一個按鈕用來點選展示異常的詳細資訊給程式設計師看的。
5.throw和throws有什麼區別?
throw關鍵字用來在程式中明確的丟擲異常,相反,throws語句用來表明方法不能處理的異常。每一個方法都必須要指定哪些異常不能處理,所以方法的呼叫者才能夠確保處理可能發生的異常,多個異常是用逗號分隔的。
6.異常處理的時候,finally程式碼塊的重要性是什麼?
無論是否丟擲異常,finally程式碼塊總是會被執行。就算是沒有catch語句同時又丟擲異常的情況下,finally程式碼塊仍然會被執行。最後要說的是,finally程式碼塊主要用來釋放資源,比如:I/O緩衝區,資料庫連線。
7.請列出 5 個執行時異常?
NullPointerException 空指標
IndexOutOfBoundsException 索引越界
ClassCastException 型別轉換異常
ArrayStoreException 當你試圖將錯誤型別的物件儲存到一個物件陣列時丟擲的異常
BufferOverflowException 寫入的長度超出了允許的長度
IllegalArgumentException 方法的引數無效
NoClassDefFoundException - JAVA執行時系統找不到所引用的類
8.try catch finally,try裡有return,finally還執行麼?
1、finally語句總會執行
即使try裡包含continue,break,return,try塊結束後,finally塊也會執行
2、如果try、catch中有return語句,finally中沒有return,那麼在finally中修改除包裝型別和靜態變數、全域性變數以外的資料都不會對try、catch中返回的變數有任何的影響(包裝型別、靜態變數會改變、全域性變數)
3、儘量不要在finally中使用return語句,如果使用的話,會忽略try、catch中的返回語句,也會忽略try、catch中的異常,遮蔽了錯誤的發生。
4、finally中避免再次丟擲異常,一旦finally中發生異常,程式碼執行將會丟擲finally中的異常資訊,try、catch中的異常將被忽略
集合部分
1、List、Map、Set三個介面,存取元素時,各有什麼特點?
1)Set集合的add有一個boolean型別的返回值,當集合中沒有某個元素時,則可以成功加入該 元素,返回結果為true;當集合中存在與某個元素equals方法相等 的元素時,則無法加入該元素, 取元素時只能用Iterator介面取得所有元素,在逐一遍歷各個元素; (2)List表示有先後順序的集合,呼叫add()方法,指定當前物件在集合中的存放位置;一個物件可 以被反覆存進集合中;每呼叫一次add()方法,該物件就會被插入集合中一次,其實,並不是把對 象本身存進了集合中,而是在集合中使用一個索引變數指向了該物件,當一個物件被add多次時, 即有多個索引指向了這個物件。List去元素時可以使用Iterator取出所有元素,在逐一遍歷,還可 以使用get(int index)獲取指定下表的元素; (3)Map是雙列元素的集合,呼叫put(key,value),要儲存一對key/value,不能儲存重複的key, 這個是根據eauals來判斷;取元素時用get(key)來獲取key所對 應的value,另外還可以獲取 全部key,全部value
2、ArrayList和LinkedList的底層實現原理?他們為什麼執行緒不安全?在多執行緒併發操作下,我們應該用什麼替代?
1.ArrayList底層通過陣列實現,ArrayList允許按序號索引元素,而插入元素需要對陣列進行移位等記憶體操作,所以索引快插入較慢;(擴容方式)一旦我們例項化了ArrayList 無參建構函式預設陣列長度為10。add方法底層如 果增加的元素超過了10個,那麼ArrayList底層會生成一個新的陣列,長度為原來陣列長度的1.5倍+1,然後將原陣列內容複製到新陣列中,並且後續加的內容都會放到新陣列中。當新陣列無法容納增加元素時,重複該過程;
2.LinkedList底層通過雙向連結串列實現,取元素時需要進行前項或後項的遍歷,插入元素時只需要記錄本項的前後 項即可,所以插入快查詢慢;
3.ArrayList和LinkedList底層方法都沒有加synchronized關鍵詞,多執行緒訪問時會出現多個執行緒先後更改資料造成得到的資料是髒資料;多執行緒併發操作下使用Vector來代替,Vector底層也是陣列,但底層方法都加synchronized關鍵字使執行緒安全,效率較ArrayList差;
3、HashMap和HashTable有什麼區別?其底層實現是什麼?CurrentHashMap的鎖機制又是如何?如果想將一個Map變為有序的,該如何實現?
1.區別: (1)HashMap沒有實現synchronized執行緒非安全,HashTable實現了synchronized執行緒安全; (2)HashMap允許key和value為null,而HashTable不允許
2.底層原理:陣列+連結串列實現
3.ConcurrentHashMap鎖分段技術:HashTable效率低下的原因,是因為所訪問HashTable的執行緒都必須競爭同一把鎖,那假如容器中有多把鎖,每一把鎖用於鎖住容器中的一部分資料,那麼當多執行緒訪問容器中不同的資料時,執行緒間就不會存在鎖競爭,從而提高併發訪問率;ConcurrentHashMap使用的就是鎖分段技術,首先將資料分成一段一段的儲存,然後給每一段資料配一把鎖,當一個執行緒佔用鎖訪問其中一個資料時,其他段的資料也能被其他執行緒訪問;
4.實現TreeMap
4.什麼是迭代器(Iterator)?
Iterator介面提供了很多對集合元素進行迭代的方法。每一個集合類都包含了可以返回迭代器例項的迭代方法。迭代器可以在迭代的過程中刪除底層集合的元素,但是不可以直接呼叫集合的remove(Object Obj)刪除,可以通過迭代器的remove()方法刪除
5.Arraylist 與 LinkedList 區別
Arraylist:
優點:ArrayList是實現了基於動態陣列的資料結構,因為地址連續,一旦資料儲存好了,查詢操作效率會比較高(在記憶體裡是連著放的)。
缺點:因為地址連續, ArrayList要移動資料,所以插入和刪除操作效率比較低。
LinkedList:
優點:LinkedList基於連結串列的資料結構,地址是任意的,所以在開闢記憶體空間的時候不需要等一個連續的地址,對於新增和刪除操作add和remove,LinedList比較佔優勢。LinkedList 適用於要頭尾操作或插入指定位置的場景
缺點:因為LinkedList要移動指標,所以查詢操作效能比較低。
6.Arraylist 與 LinkedList 應用場景?
當需要對資料進行對此訪問的情況下選用ArrayList,當需要對資料進行多次增加刪除修改時採用LinkedList。
7.Collection 和 Collections的區別
Collection是集合類的上級介面,繼承與他的介面主要有Set 和List.Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各種集合的搜尋、排序、執行緒安全化等操作(帶s的基本都是工具類,如Arrays)
8.為何Map介面不繼承Collection介面?
儘管Map介面和它的實現也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map繼承Collection毫無意義,反之亦然。
如果Map繼承Collection介面,那麼元素去哪兒?Map包含key-value對,它提供抽取key或value列表集合的方法,但是它不適合“一組物件”規範。
9.當兩個物件的hashcode相同會發生什麼?
因為hashcode相同,所以它們的bucket位置相同,‘碰撞’會發生。因為HashMap使用連結串列儲存物件,這個Entry(包含有鍵值對的Map.Entry物件)會儲存在連結串列中。
10.HashMap和Hashtable有什麼區別?
1、HashMap是非執行緒安全的,HashTable是執行緒安全的。
2、HashMap的鍵和值都允許有null值存在,而HashTable則不行。
3、因為執行緒安全的問題,HashMap效率比HashTable的要高。
4、Hashtable是同步的,而HashMap不是。因此,HashMap更適合於單執行緒環境,而Hashtable適合於多執行緒環境。
一般現在不建議用HashTable, ①是HashTable是遺留類,內部實現很多沒優化和冗餘。②即使在多執行緒環境下,現在也有同步的ConcurrentHashMap替代,沒有必要因為是多執行緒而用HashTable。
11.List 和 Set 區別
List,Set都是繼承自Collection介面
List特點:元素有放入順序,元素可重複
Set特點:元素無放入順序,元素不可重複,重複元素會覆蓋掉
(注意:元素雖然無放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實是固定的,加入Set 的Object必須定義equals()方法 ,另外list支援for迴圈,也就是通過下標來遍歷,也可以用迭代器,但是set只能用迭代,因為他無序,無法用下標來取得想要的值。)
12.Set和List對比
Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。
List:和陣列類似,List可以動態增長,查詢元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變。
13.當兩個物件的hashcode相同會發生什麼?
因為hashcode相同,所以它們的bucket位置相同,‘碰撞’會發生。因為HashMap使用連結串列儲存物件,這個Entry(包含有鍵值對的Map.Entry物件)會儲存在連結串列中。
14.如果兩個鍵的hashcode相同,你如何獲取值物件?
當我們呼叫get()方法,HashMap會使用鍵物件的hashcode找到bucket位置,然後會呼叫keys.equals()方法去找到連結串列中正確的節點,最終找到要找的值物件。
15.有沒有可能兩個不相等的物件有相同的hashcode
有可能,兩個不相等的物件可能會有相同的 hashcode 值,這就是為什麼在 hashmap 中會有衝突。如果兩個物件相等,必須有相同的hashcode 值,反之不成立。
16.HashMap、LinkedHashMap、TreeMap的區別。**
1、HashMap是根據鍵的hashcode值儲存資料,根據鍵可以直接獲取它的值,具有很快的訪問速度,取得的資料完全是隨機的
2、LinkedHashMap儲存了記錄的插入順序,在使用Iterator進行遍歷的時候,先得到的肯定是先插入的資料,可以在構造時帶引數,按照應用次數來進行排序
3、TreeMap實現SortMap介面,能夠把它儲存的記錄根據鍵排序。預設的是升序排序,也可以指定排序的比較器,進行遍歷的時候得到的是排序過的記錄。
17.HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底層實現。**
1、HashMap是java資料結構中兩大結構陣列和連結串列的組合。HashMap底層陣列,陣列中的每一項又是一個連結串列。程式會先根據key的hashcode()方法返回值決定該Entry在陣列中的
儲存位置,如果該位置上沒有元素,就會將元素放置在此位置上,如果兩個Entry的key相同,會呼叫equals,返回值是true則覆蓋原來的value值,返回false則會形成Entry鏈,位於頭部。
2、ArrrayList的底層實現是陣列,在執行add操作時,會先檢查陣列 大小是否可以容納新的元素,如果不夠就會進行擴容。然後會將原來的資料拷貝到新的陣列中。
3、LinkedList底層是一個連結串列,其實現增刪改查和資料結構中的操作完全相同,而且插入是有序的。
4、LinkedHashMap的底層結構式是雙連結串列,其他的邏輯處理與HashMap一致,同樣沒有鎖保護,多執行緒使用時存在風險。
5、ConcurrentHashMap是segment陣列結構和HashEntry陣列結構組成的,segment在ConcurrentHashMap中充當鎖的角色,HashEntry用於儲存鍵值對資料。segment的結構是陣列和連結串列,一個segment中有一個HashEntry,每個HashEntry是一個連結串列結構的元素。對HashEntry中的資料進行修改時,需要先獲得它所對應的segment鎖。每個ConcurrentHashMap預設有16個segment。
18.==和 equals hashCode 的區別?
基本資料型別: ==比較的是內容 引用資料型別: ==比的是地址值,equals預設比地址值,重寫按照規則比較,hashCode
19.自然排序Comparble和比較器排序Comparator的異同點?
相同點:
返回值的規則:
-
如果返回值為負數,表示當前存入的元素是較小值,存左邊
-
如果返回值為0,表示當前存入的元素跟集合中元素重複了,不存
-
如果返回值為正數,表示當前存入的元素是較大值,存右邊
不同點:
1.用到的介面不同
-
自然排序: 自定義類實現Comparable介面,重寫compareTo方法,根據返回值進行排序
-
比較器排序: 建立TreeSet物件的時候傳遞Comparator的實現類物件,重寫compare方法,根據返回值進行排序
2.使用場景不同
-
自然排序能滿足大部分情況
-
儲存沒有修改許可權的類時可以使用
泛型
1.為什麼使用泛型?
它提供了編譯時型別安全檢測機制,把執行時期的問題提前到了編譯期間
避免了強制型別轉換
2.泛型用在什麼地方?
類,方法,介面
3.如何使用泛型類?
建立泛型類物件時,必須要給這個泛型確定具體的資料型別
樹
1.什麼是二叉樹?
任意節點的子節點不超過2
2.什麼是二叉查詢樹?
每個節點最多有兩個子節點,左邊比當前節點小,右邊比當前節點大
3.什麼是平衡二叉樹?
二叉樹左右子樹的樹高差不超過1,任意節點的左右子樹都是平衡二叉樹
通過左旋右旋保持樹的平衡
序列化
1.什麼是 Java 序列化?
序列化就是一種用來處理物件流的機制,所謂物件流也就是將物件的內容進行流化。
可以對流化後的物件進行讀寫操作,也可將流化後的物件傳輸於網路之間。
序列化是為了解決在對物件流進行讀寫操作時所引發的問題。
反序列化的過程,則是和序列化相反的過程。
另外,我們不能將序列化侷限在 Java 物件轉換成二進位制陣列,例如說,我們將一個 Java 物件,轉換成 JSON 字串,或者 XML 字串,這也可以理解為是序列化。
2.如何實現 Java 序列化?
將需要被序列化的類,實現 Serializable 介面,該介面沒有需要實現的方法,implements Serializable 只是為了標註該物件是可被序列化的。
序列化
然後,使用一個輸出流(如:FileOutputStream)來構造一個 ObjectOutputStream(物件流)物件
接著,使用 ObjectOutputStream 物件的 #writeObject(Object obj) 方法,就可以將引數為 obj 的物件寫出(即儲存其狀態)。
反序列化
要恢復的話則用輸入流。
3.Java 序列話中,如果有些欄位不想進行序列化怎麼辦?
對於不想進行序列化的變數,使用 transient 關鍵字修飾。
當物件被序列化時,阻止例項中那些用此關鍵字修飾的的變數序列化。
當物件被反序列化時,被 transient 修飾的變數值不會被持久化和恢復。
transient 只能修飾變數,不能修飾類和方法。
4.物件操作流是字元流還是位元組流?
位元組流
5.如何在讀寫檔案時指定字符集?
jdk11之前:
使用轉換流InputStreamReader(輸入轉換流)位元組轉換字元橋樑/OutputStreamWriter(輸出轉換流)字元轉位元組橋樑
jdk11之後
直接使用FileReader指定
6.字元緩衝流特有方法?
readLine():讀取一整行,到達尾處為null
newLine():跨平臺換行
7.為什麼使用物件流?
在開發中,經常需要將物件的資訊儲存到磁碟中,如果使用前面所學的知識來實現,會非常的繁瑣。使用物件流就非常的方便
物件操作流可以將物件以位元組的形式寫到本地檔案中,直接開啟是看不懂的,需要時可以再次用物件操作流讀到記憶體中
多執行緒
1.什麼是執行緒?
執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程式之中,是程式中的實際運作單位。執行緒是程式的一部分,是程式中的單個控制流,是一條執行路徑
2.執行緒和程式有什麼區別?
執行緒是程式的子集,一個程式可以有很多執行緒,每條執行緒並行執行不同的任務。不同的程式使用不同的記憶體空間,而所有的執行緒共享一片相同的記憶體空間。
3.如何在Java中實現執行緒?
繼承Thread:
可以直接呼叫Thread中的方法
實現Runnable介面:
實現Runnable介面,將實現類作為引數傳遞給Thread物件
實現Callable介面:
實現Callabale介面,建立FutureTask物件,將Callable作為引數傳遞給FutureTask物件,再將FutureTask物件傳遞給Thread類
4.用Runnable還是Thread?
Java不支援類的多重繼承,但允許你呼叫多個介面。所以如果你要繼承其他類,當然是呼叫Runnable介面好了。
Thread:實際中用的相對較少,擴充套件性太差
Runnable,Callable:
擴充套件性比較強,優先使用Runnable介面,需要執行完有返回值可以選擇Callable介面
5.Thread 類中的start() 和 run() 方法有什麼區別?
start()方法被用來啟動新建立的執行緒,而且start()內部呼叫了run()方法,這和直接呼叫run()方法的效果不一樣。
當你呼叫run()方法的時候,只會是在原來的執行緒中呼叫,沒有新的執行緒啟動,start()方法才會啟動新執行緒。
6.Java中Runnable和Callable有什麼不同?
Runnable和Callable都代表那些要在不同的執行緒中執行的任務。Runnable從JDK1.0開始就有了,Callable是在JDK1.5增加的。它們的主要區別是Callable的 call() 方法可以返回值和丟擲異常,而Runnable的run()方法沒有這些功能。Callable可以返回裝載有計算結果的Future物件。
7.Java記憶體模型是什麼?
Java記憶體模型規定和指引Java程式在不同的記憶體架構、CPU和作業系統間有確定性地行為。它在多執行緒的情況下尤其重要。Java記憶體模型對一個執行緒所做的變動能被其它執行緒可見提供了保證,它們之間是先行發生關係。這個關係定義了一些規則讓程式設計師在併發程式設計時思路更清晰。比如,先行發生關係確保了:
-
執行緒內的程式碼能夠按先後順序執行,這被稱為程式次序規則。
-
對於同一個鎖,一個解鎖操作一定要發生在時間上後發生的另一個鎖定操作之前,也叫做管程鎖定規則。
-
前一個對volatile的寫操作在後一個volatile的讀操作之前,也叫volatile變數規則。
-
一個執行緒內的任何操作必需在這個執行緒的start()呼叫之後,也叫作執行緒啟動規則。
-
一個執行緒的所有操作都會線上程終止之前,執行緒終止規則。
-
一個物件的終結操作必需在這個物件構造完成之後,也叫物件終結規則。
-
可傳遞性
8.Java中的volatile 變數是什麼?
volatile是一個特殊的修飾符,只有成員變數才能使用它。在Java併發程式缺少同步類的情況下,多執行緒對成員變數的操作對其它執行緒是透明的。volatile變數可以保證下一個讀取操作會在前一個寫操作之後發生,就是上一題的volatile變數規則。
9.什麼是執行緒安全?Vector是一個執行緒安全類嗎?
多個執行緒可能會同時執行同一段程式碼。如果每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是執行緒安全的。一個執行緒安全的計數器類的同一個例項物件在被多個執行緒使用的情況下也不會出現計算失誤。很顯然你可以將集合類分成兩組,執行緒安全和非執行緒安全的。Vector 是用同步方法來實現執行緒安全的, 而和它相似的ArrayList不是執行緒安全的。
10.Java中如何停止一個執行緒?
當run() 或者 call() 方法執行完的時候執行緒會自動結束,如果要手動結束一個執行緒,你可以用volatile 布林變數或設定某個變數達到一定值的時候,來退出run()方法的迴圈或者是取消任務來中斷執行緒。
11.Java中notify 和 notifyAll有什麼區別?
notify()方法不能喚醒某個具體的執行緒,所以只有一個執行緒在等待的時候它才有用武之地。
而notifyAll()喚醒所有執行緒並允許他們爭奪鎖確保了至少有一個執行緒能繼續執行
12. 什麼是執行緒池? 為什麼要使用它?
建立執行緒要花費昂貴的資源和時間,如果任務來了才建立執行緒那麼響應時間會變長,而且一個程式能建立的執行緒數有限。為了避免這些問題,在程式啟動的時候就建立若干執行緒來響應處理,它們被稱為執行緒池,裡面的執行緒叫工作執行緒。從JDK1.5開始,Java API提供了Executor框架讓你可以建立不同的執行緒池。比如單執行緒池,每次處理一個任務;數目固定的執行緒池或者是快取執行緒池(一個適合很多生存期短的任務的程式的可擴充套件執行緒池)
13.如何寫程式碼來解決生產者消費者問題?
在現實中你解決的許多執行緒問題都屬於生產者消費者模型,就是一個執行緒生產任務供其它執行緒進行消費,你必須知道怎麼進行執行緒間通訊來解決這個問題。比較低階的辦法是用wait和notify來解決這個問題,比較讚的辦法是用Semaphore 或者 BlockingQueue來實現生產者消費者模型
14.Java多執行緒中的死鎖
死鎖是指兩個或兩個以上的程式在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。這是一個嚴重的問題,因為死鎖會讓你的程式掛起無法完成任務,死鎖的發生必須滿足以下四個條件:
-
互斥條件:一個資源每次只能被一個程式使用。
-
請求與保持條件:一個程式因請求資源而阻塞時,對已獲得的資源保持不放。
-
不剝奪條件:程式已獲得的資源,在末使用完之前,不能強行剝奪。
-
迴圈等待條件:若干程式之間形成一種頭尾相接的迴圈等待資源關係。
避免死鎖最簡單的方法就是阻止迴圈等待條件,將系統中所有的資源設定標誌位、排序,規定所有的程式申請資源必須以一定的順序(升序或降序)做操作來避免死鎖。
15.Java中synchronized 和 ReentrantLock 有什麼不同?
這兩種方式最大區別就是對於Synchronized來說,它是java語言的關鍵字,是原生語法層面的互斥,需要jvm實現。而ReentrantLock它是JDK 1.5之後提供的API層面的互斥鎖,需要lock()和unlock()方法配合try/finally語句塊來完成。
16.詳談Synchronized
當Synchronized關鍵字修飾一個方法的時候,該方法叫做同步方法:java中的每個物件都有一個鎖(lock)或者叫做監視器(monitor),當訪問某個物件的synchronized方法的時候,表示將物件上鎖,此時其它任何執行緒都無法再去訪問synchronized方法了,直到之前的那個執行緒執行方法完畢後(或者是丟擲了異常),那麼將該物件的鎖釋放掉,其他執行緒才有可能再去訪問該synchronized方法。
注意1:
如果一個物件有多個synchronized方法,某一個時刻某個執行緒已經進入到了某個synchronized方法,那麼在該方法沒有執行完畢前,其它執行緒是無法訪問該物件的任何synchronzed方法的。
注意2:
如果某個Synchronized方法是static的,那麼當執行緒訪問該方法時,它鎖的並不是Synchronized方法所在的物件,而是Synchronized方法所在的物件所物件的Class物件,因為java中無論一個類有多少個物件,這些物件會對應唯一一個class物件,因此當執行緒分別訪問同一個類的兩個物件的兩個static Synchronized方法的時候,他們執行的順序也是順序的,也就是說一個執行緒先去執行方法,執行完畢後另一個執行緒才開始執行。
注意3:
jdk1.6之後對synchronized(偏向鎖(根本就不加鎖)、輕量級鎖(CAS),重量級鎖(悲觀鎖))進行了大量的優化
17.在Java中Lock介面與synchronized塊的區別是什麼?
.用法不一樣。synchronized既可以加在方法上,也可以載入特定的程式碼塊上,括號中表示需要鎖的物件。而Lock需要顯示地指定起始位置和終止位置。synchronzied是託管給jvm執行的,Lock鎖定是通過程式碼實現的。
2.在效能上來說,如果競爭資源不激烈,兩者的效能是差不多的,而當競爭資源非常激烈時(即有大量執行緒同時競爭),此時Lock的效能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。
3.鎖的機制不一樣。synchronized獲得鎖和釋放的方式都是在塊結構中,而且是自動釋放鎖。而Lock則需要開發人員手動去釋放,並且必須在finally塊中釋放,否則會引起死鎖問題的發生。
4.Lock是一個介面,而synchronized是Java中的關鍵字,synchronized是內建的語言實現;
5.synchronized在發生異常時,會自動釋放執行緒佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖
18.synchronized 的原理是什麼?有什麼不足?
synchronized是 Java 內建的關鍵字,它提供了一種獨佔的加鎖方式。
synchronized的獲取和釋放鎖由JVM實現,使用者不需要顯示的釋放鎖,非常方便。
然而,synchronized 也有一定的侷限性。
當執行緒嘗試獲取鎖的時候,如果獲取不到鎖會一直阻塞。
如果獲取鎖的執行緒進入休眠或者阻塞,除非當前執行緒異常,否則其他執行緒嘗試獲取鎖必須一直等待。
19.關於成員變數和區域性變數
如果一個變數是成員變數,那麼多個執行緒對同一個物件的成員變數進行操作的時候,他們對該成員變數是彼此影響的,也就是說一個執行緒對成員變數的改變會影響到另外一個執行緒;如果一個變數是區域性變數,那麼每個執行緒都會有一個該區域性變數的拷貝,一個執行緒對該區域性變數的改變不會影響到其它的執行緒。
20. 如果你提交任務時,執行緒池佇列已滿。會時發會生什麼?
如果一個任務不能被排程執行那麼ThreadPoolExecutor’s submit()方法將會丟擲一個RejectedExecutionException異常。
21.volatile關鍵字的作用是?
保證變數的可見性。
在java記憶體結構中,每個執行緒都是有自己獨立的記憶體空間(此處指的執行緒棧)。當需要對一個共享變數操作時,執行緒會將這個資料從主存空間複製到自己的獨立空間內進行操作,然後在某個時刻將修改後的值重新整理到主存空間。這個中間時間就會發生許多奇奇怪怪的執行緒安全問題了,volatile就出來了,它保證讀取資料時只從主存空間讀取,修改資料直接修改到主存空間中去,這樣就保證了這個變數對多個操作執行緒的可見性了。換句話說,被volatile修飾的變數,能保證該變數的 單次讀或者單次寫 操作是原子的。
但是執行緒安全是兩方面需要的 原子性(指的是多條操作)和可見性。volatile只能保證可見性,synchronized是兩個均保證的。
volatile輕量級,只能修飾變數;synchronized重量級,還可修飾方法。
volatile不會造成執行緒的阻塞,而synchronized可能會造成執行緒的阻塞。
22.守護執行緒和非守護執行緒有什麼區別?
程式執行完畢,JVM 會等待非守護執行緒完成後關閉,但是 JVM 不會等待守護執行緒
23.執行緒的生命週期?
執行緒的生命週期包含5個階段,包括:新建、就緒、執行、阻塞、銷燬。
-
新建:就是剛使用new方法,new出來的執行緒;
-
就緒:就是呼叫的執行緒的start()方法後,這時候執行緒處於等待CPU分配資源階段,誰先搶的CPU資源,誰開始執行;
-
執行:當就緒的執行緒被排程並獲得CPU資源時,便進入執行狀態,run方法定義了執行緒的操作和功能;
-
阻塞:在執行狀態的時候,可能因為某些原因導致執行狀態的執行緒變成了阻塞狀態,比如sleep()、wait()之後執行緒就處於了阻塞狀態,這個時候需要其他機制將處於阻塞狀態的執行緒喚醒,比如呼叫notify或者notifyAll()方法。喚醒的執行緒不會立刻執行run方法,它們要再次等待CPU分配資源進入執行狀態;
-
銷燬:如果執行緒正常執行完畢後或執行緒被提前強制性的終止或出現異常導致結束,那麼執行緒就要被銷燬,釋放資源;
24.wait和sleep,notify()鎖方面區別?
wait:讓執行緒等待,同時立即釋放鎖
sleep():讓執行緒休眠,但是不會釋放鎖
notify()或notifyAll(): 喚醒等待的執行緒,但是不會立即釋放鎖
25.什麼情況下會出現執行緒安全問題?
多執行緒環境
有共享資料
有對共享資料的操作
26.Java中規定了執行緒有哪幾種狀態?
新建、就緒、阻塞、等待、計時等待、死亡
27.什麼是原子性?
所謂的原子性就是完成功能的所有操作要麼都執行,要麼都不執行
28.Java中哪些操作是原子操作?
除了long和double之外的所有原始型別的賦值
所有volatile變數的賦值
java.concurrent.Atomic *類的所有操作
29.什麼是CAS演算法?
1.當預期值E==主記憶體中的值V,此時可以進行修改,將V改成新值
2.當預期值E!=主記憶體中的值V時,將主記憶體中的已經改變的值更新到自己的工作記憶體中,再次嘗試比較,直到預期值E等於主記憶體中的值V,才可以修改。這個過程稱為自旋
30.synchronized和CAS的區別?
相同點:
在多執行緒情況下,都可以保證共享資料的安全性。
不同點:
synchronized總是從最壞的角度出發,認為每次獲取資料的時候,別人都有可能修改。所以在每 次操作共享資料之前,都會上鎖。(悲觀鎖)
CAS是從樂觀的角度出發,假設每次獲取資料別人都不會修改,所以不會上鎖。只不過在修改共享資料的時候,會檢查一下,別人有沒有修改過這個資料。如果別人修改過,那麼我再次獲取現在最新的值。如果別人沒有修改過,那麼我現在直接修改共享資料的值.(樂觀鎖)
31.併發容器Hashtable和ConcurrentHashMap特點?
Hashtable:
-
Hashtable採取悲觀鎖synchronized的形式保證資料的安全性
-
只要有執行緒訪問,會將整張表全部鎖起來,所以Hashtable效率低下
ConcurrentHashMap:
-
採用sychronized+cas
-
執行緒安全,效率比Hashtable高,比HashMap低
反射
1.Java反射機制的作用?
1)在執行時判斷任意一個物件所屬的類。
2)在執行時判斷任意一個類所具有的成員變數和方法。
3)在執行時任意呼叫一個物件的方法
4)在執行時構造任意一個類的物件
2.什麼是反射機制?
簡單說,反射機制值得是程式在執行時能夠獲取自身的資訊。在java中,只要給定類的名字,那麼就可以通過反射機制來獲得類的所有資訊。
3.哪裡用到反射機制?
Spring 框架的 IoC 基於反射建立物件和設定依賴屬性。
Spring MVC 的請求呼叫對應方法,也是通過反射。
JDBC 的 Class#forName(String className) 方法,也是使用反射。
4.反射機制的優缺點?
靜態編譯:在編譯時確定型別,繫結物件,即通過
動態編譯:執行時確定型別,繫結物件。動態編譯最大限度的發揮了java的靈活性,體現了多型的應用,有利於降低類之間的耦合性。
一句話,反射機制的優點就是可以實現動態建立物件和編譯,體現出很大的靈活性,特別是在J2EE的開發中
它的靈活性就表現的十分明顯。比如,一個大型的軟體,不可能一次就把把它設計的很完美,當這個程式編
譯後,釋出了,當發現需要更新某些功能時,我們不可能要使用者把以前的解除安裝,再重新安裝新的版本,假如
這樣的話,這個軟體肯定是沒有多少人用的。採用靜態的話,需要把整個程式重新編譯一次才可以實現功能
的更新,而採用反射機制的話,它就可以不用解除安裝,只需要在執行時才動態的建立和編譯,就可以實現該功
能。
它的缺點是對效能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它
滿足我們的要求。這類操作總是慢於只直接執行相同的操作
5.反射中,Class.forName 和 ClassLoader 區別
java中class.forName()和classLoader都可用來對類進行載入。
class.forName()前者除了將類的.class檔案載入到jvm中之外,還會對類進行解釋,執行類中的static塊。
而classLoader只幹一件事情,就是將.class檔案載入到jvm中,不會執行static中的內容,只有在newInstance才會去執行static塊。
6.什麼是雙親委派模型?
如果一個類載入器收到了類載入請求,它並不會自己先去載入,而是把這個請求委託給父類的載入器去執行,如果父類載入器還存在其父類載入器,則進一步向上委託,依次遞迴,請求最終將到達頂層的啟動類載入器,如果父類載入器可以完成類載入任務,就成功返回,倘若父類載入器無法完成此載入任務,子載入器才會嘗試自己去載入,這就是雙親委派模式
7.為什麼要有雙親委派模型?
為了保證類的全域性唯一性,如果自定義類與Java核心類庫中的類重名了,會被編譯但不會不執行
8.怎麼利用反射使用私有成員?
setAccessible(boolean flag)
1.什麼是三次握手?
-
客戶端向伺服器發出取消連線請求
-
伺服器向客戶端返回一個響應,告訴客戶端收到了請求
-
客戶端向伺服器端再次發出確認資訊建立連線
2.什麼是四次揮手?
-
1.客戶端向伺服器發出取消連線請求
-
2.伺服器向客戶端返回一個響應,表示收到客戶端取消請求
-
3.伺服器向客戶端發出確認資訊
-
4.客戶端再次傳送確認資訊,連線取消
3.TCP通訊注意事項?
-
accept方法是阻塞的,作用就是等待客戶端連線
-
客戶端建立物件並連線伺服器,此時是通過三次握手協議,保證跟伺服器之間的連線
-
針對客戶端來講,是往外寫的,所以是輸出流 針對伺服器來講,是往裡讀的,所以是輸入流
-
read方法也是阻塞的
-
客戶端在關流的時候,還多了一個往伺服器寫結束標記的動作
-
最後一步斷開連線,通過四次揮手協議保證連線終止