二、JavaSE
求職技能要求:熟練掌握JavaSE語法,熟練使用JavaSE的常用API。
在面試中一般不會考核JavaSE語法和常用API的用法(除非面試官招聘的是實習生),但是會問到一些偏理論的知識,比如:常見集合的內部資料結構,以及部分API的底層原理等,主要是考核應聘者的Java功底是否紮實。
Tips:面試的時候,大致有這樣的規律,越是大型的網際網路公司越容易問到底層原理和資料結構,未來如果我們想跳槽到大廠,那麼一定要在底層原理和資料結構上下功夫。
(一)Java的基礎概念1. 面向物件的特徵技能要求:深入理解Java的面向物件思想。
封裝 繼承 多型 (抽象)。
2. Java的基本資料型別有哪些面試頻次:中,屬於基礎必須知識,在中小企業面試時比較常見。
byte(2) short(2) int(4) long(8) char(2) boolean float(4) double(8)
Tips:boolean型別代表了1個位元組的資訊(true或者false),但是沒有給出精準的位元組數。《Java虛擬機器規範》給出了boolean型別佔4個位元組的定義,具體還要看虛擬機器實現是否按照規範來,所以1個位元組、4個位元組都是有可能的。
3. Java中==和equals的區別面試頻次:中,在中小企業面試時比較常見。
== : 它的作用是判斷兩個物件的地址是不是相等。即:判斷兩個物件是不是同一個物件。(基本資料型別==比較的是值,引用資料型別==比較的是記憶體地址)。
equals : 它的作用也是判斷兩個物件是否相等,但它一般有兩種使用情況,如下:
情況1:類沒有覆寫equals() 方法。則透過 equals() 比較該類的兩個物件時,等價於透過“==”比較這兩個物件。
情況2:類覆寫了equals() 方法。若它們的內容相等,則返回 true (即,認為這兩個物件相等)。
4. String、StringBuffer、StringBuilder三者之間的區別面試頻次:中,基礎必備知識。
可變性:
String類中使用final關鍵字字元陣列儲存字串,private final char value[],所以String物件是不可變的,而StringBuilder與 StringBuffer是可變的。
執行緒安全性:
String中的物件是不可變的,因此是執行緒安全的。StringBuffer對方法加了同步鎖是執行緒安全的,StringBuilder是非執行緒安全的。
效能:
每次對String型別進行改變的時候,都會生成一個新的String物件,因此效能最低。而StringBuffer和StringBuilder的修改則是對本身進行操作,而不是生成新的物件,因此效能較高。
StringBuilder相比StringBuffer能獲得 10%~15% 左右的效能提升,但執行緒不安全。
對於三者使用的總結:
1. 操作少量的資料 => 使用String
2. 單執行緒操作字串緩衝區下操作大量資料 => 使用StringBuilder
3. 多執行緒操作字串緩衝區下操作大量資料 => 使用StringBuffer
5. JDK8的新特性面試頻次:中。
Java8釋出於2014年3月18號,新增了非常多的特性,要求面試時能說出如下幾點即可:
① Lambda表示式
Lambda允許把函式作為一個方法的引數。
1. new Thread(()-> System.out.println("abc")).start();
② 方法引用
方法引用允許直接引用已有Java類或物件的方法或構造方法。
1. ArrayList<String> list = new ArrayList<>();2. list.add("a");3. list.add("b");4. list.add("c");5. list.forEach(System.out::println);
上例中我們將System.out::println方法作為靜態方法來引用。
有且僅有一個抽象方法的介面叫做函式式介面,函式式介面可以被隱式轉換為Lambda表示式。通常函式式介面上會新增@FunctionalInterface註解。
④ 介面允許定義預設方法和靜態方法
從JDK8開始,允許介面中存在一個或多個預設非抽象方法和靜態方法。
⑤ Stream API
新新增的Stream API(java.util.stream)把真正的函數語言程式設計風格引入到Java中。這種風格將要處理的元素集合看作一種流,流在管道中傳輸,並且可以在管道的節點上進行處理,比如篩選,排序,聚合等。
1. List<String> list = Arrays.asList("abc", "", "abc", "bc", "efg", "abcd", "def", "jkl");2. 3. list.stream()//獲取集合的流物件4. .filter(string -> !string.isEmpty())//對資料進行過濾操作,過濾掉空字串5. .distinct()//去重6. .forEach(a -> System.out.println(a));
⑥ 日期/時間類改進
之前的JDK自帶的日期處理類非常不方便,我們處理的時候經常是使用的第三方工具包,比如commons-lang包等。不過JDK8出現之後這個改觀了很多,比如日期時間的建立、比較、調整、格式化、時間間隔等。
這些類都在java.time包下,LocalDate/LocalTime/LocalDateTime。
⑦ Optional 類
Optional類是一個可以為null的容器物件。如果值存在則isPresent()方法會返回true,呼叫get()方法會返回該物件。
1. String string = "abc";2. 3. Optional<String> optional = Optional.of(string);4. boolean present = optional.isPresent();5. String value = optional.get();6. System.out.println(present+"/"+value);
⑧ Java8 Base64實現
Java 8 內建了 Base64 編碼的編碼器和解碼器。
(二)Java的異常體系1. Java的異常體系技能要求:熟練掌握Java的異常體系。
面試頻次:中。(翻譯成大白話:能夠知道Java中異常的分類以及相互之間的關係,能夠使用try-cath-finally進行異常的捕獲操作。)
複習建議:透過原始碼去檢視Java中異常的繼承關係,同時需要理解並記憶下面一段話。
Java中異常體系的頂級父類是Throwable,它有兩個子類,Error和Exception,其中Error是嚴重的錯誤(一般是底層或記憶體等方面的錯誤),該類錯誤不需要在方法上throws更不需要catch,這種錯誤是不應該出現的異常,常見的有StackOverflowError和OutOfMemoryError。另外一個Exception是我們開發時需要處理的異常,子類眾多,可以分為執行時異常(RuntimeException)和編譯時異常(CheckedException)。
執行時異常指編譯器編譯時不進行強制檢查的異常,但是在執行時可能發生的異常,比如:NullPointerException、IndexOutOfBoundsException、ClassNotFoundException。
編譯時異常是指編譯器在編譯時就會強制檢查,必須在方法上throws或者方法中catch的異常。
Tips:為了程式碼的健壯性,不管是執行時異常還是編譯時異常,在寫程式碼時都需要避免或進行異常處理。
Java異常體系結構圖
Throwable類的兩個子類
Error類註解
Exception類註解
RuntimeException類註解
2. throws和throw的區別throws用在方法的簽名上,代表了當前方法可能會丟擲哪些異常,呼叫該方法時需要進行異常處理,throw用在方法之內,代表對外丟擲一個具體的異常物件。
(三)Java的集合體系1. 整體介紹Java的集合體系技能要求:熟練掌握Java的集合體系。
面試出現頻次:高。
集合分為單列集合和雙列集合,單列集合的頂級介面是Collection(雖然Collection繼承了Iterator),它有兩個常見的子介面Set和List。Set子類中最常見的是HashSet、LinkedHashSet、TreeSet。List子類中最常見的是ArrayList、LinkedList、Vector(很少用)。
雙列集合的頂級介面是Map,它有三個常見的實現類,HashMap、LinkedHashMap、TreeMap。
集合體系框架圖
2. ArrayList、Vector、LinkedList的區別面試出現頻次:高。
Vector和ArrayList一樣,也是透過陣列實現的,不同的是它是執行緒安全的,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。當集合中元素的數目大於當前集合陣列的長度時,Vector增長率為當前陣列長度的100%,而Arraylist增長率為當前陣列長度的50%。
3. HashMap的底層資料結構面試出現頻次:非常高。
HashMap底層包含了很多知識點,很考驗程式設計師的基本功,被問到的機率很高,強烈建議大家對其原始碼進行更多的瞭解。
Tips:
1. 看HashMap的原始碼時不要將整個類從頭到尾依次去看,而是從建構函式和主要方法(put、get)進入檢視。
2. 或者,可以先看一些關於HashMap原始碼的文章,然後再查原始碼對別人文章中的核心觀點進行驗證。
3. 看原始碼時不需要將每一行程式碼都讀懂,主要是看關鍵程式碼的實現即可。
HashMap底層資料結構
參考話術:
HashMap的底層資料結構為陣列+連結串列或紅黑樹結構,當連結串列長度大於8時會升級為紅黑樹,當紅黑樹節點小於6時又會退化為連結串列。
當呼叫HashMap的空參建構函式的時候,HashMap僅僅將預設的載入因子常量DEFAULT_LOAD_FACTOR=0.75賦值給了loadFactory成員變數。
當第一次呼叫put(k,v)方法的時候,HashMap會建立一個預設容量為DEFAULT_INITIAL_CAPACITY=16的陣列,型別為Node<k,v>,Node本身是連結串列結構,且是單向連結串列。然後HashMap會根據k,透過自有的hash函式計算出hash值,然後取hash值的低四位,這樣就得到一個介於0-15之間的數值作為要把資料放到陣列的角標,但是當k為null的時候,HashMap會把資料放到陣列的第一個位置。
如果繼續put資料,出現k的hash值和已有資料相同的情況,則把該節點作為當前陣列位置上節點的後一個節點即可,這就構成了單向連結串列結構。如果這個連結串列長度大於等於8,則把該連結串列透過treeifyBin函式轉化為紅黑樹結構。(因為紅黑樹的查詢效果比連結串列要高)。
當put的資料超過DEFAULT_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR = 16*0.75 = 12時,HashMap會進行第一次擴容,每次擴容是按照2倍遞增進行的。擴容後,會重新將節點的位置進行打散存放。
HashMap擴容時連結串列或樹的重新分佈
4. HashMap、Hashtable、ConcurrentHashMap的區別① HashMap是執行緒不安全的,Hashtable和ConcurentHashMap是執行緒安全的。
② ConcurrentHashMap在JDK7中採用Segment分段鎖技術來保證執行緒安全,在JDK8中ConcurrentHashMap取消了Segment分段鎖,採用粒度更小的CAS和synchronized機制來保證併發安全,效能比較高,而Hashtable則使用Synchronized關鍵字來實現執行緒安全的,效能比較低,因此該類已經被替代。
(四)BIO、NIO、AIO的區別Tips:如果應聘的崗位對高併發有較高要求,則被問到的機率就很高,面試前就需要對該塊知識進行“惡補”。
參見部落格:
https://www.imooc.com/article/265871
BIO:Block IO,同步阻塞式IO,就是我們平常使用的傳統IO,它的特點是模式簡單使用方便,併發處理能力低。
常見類:InputStream、OutputStream、Reader、Writer。
NIO:New IO,同步非阻塞IO,是傳統IO的升級,客戶端和伺服器端透過Channel(通道)通訊,實現了多路複用。 常見類:Channels、Buffers、Selectors。
AIO:Asynchronous IO是NIO 的升級,也叫 NIO2,實現了非同步非堵塞 IO,非同步IO的操作基於事件和回撥機制。常見類:AsynchronousChannel。