1. 程式人生 > >就因為沒看這篇文章面試失敗了

就因為沒看這篇文章面試失敗了

# 前言 熬夜整理了一份java基礎面試題,希望大家支援,如果文中有錯誤希望大家指正; 公眾號:**知識追尋者** > 知識追尋者(Inheriting the spirit of open source, Spreading technology knowledge;) # 一 java基礎面試 ## 1.1面向物件和麵向過程的區別 - 面向過程: 優點:**效能比面向物件高**,因為類呼叫時需要例項化,開銷比較大,比較消耗 資源 應用場景:微控制器、嵌入式開發、Linux/Unix ; 缺點:沒有面向物件易維護、易複用、易擴充套件 - 面向物件 優點:因為面向物件有封裝、繼承、多型性的特 性,可以設計出低耦合的系統,故易維護、易複用、易擴充套件; 應用場景:網頁開發,後臺開發等; 缺點:效能比面向過程低 ## 1.2 面向物件的特性 - **封裝**: 將一個物件的屬性私有化,並提供一個對外訪問的方法; - **繼承**:在已有類的基礎上建立新類;提供繼承資訊的類被稱為父類(超類、基類);得到繼 承資訊的類被稱為子類(派生類) - **多型**:一個物件的多種表現形態;用同樣的物件引用呼叫同樣的方法但是做了不同的事情;可以向上轉型和向下轉型 多型實現形式: 重寫:子類對父類方法的重寫; 覆蓋:實現介面,並覆蓋方法; ## 1.3 抽象 抽象是指將物件抽象為具體類的過程;抽象只關注物件有哪些屬性和行為(方法); ## 1.4 Java語言特點 1. 簡單易學; 2. 面向物件(封裝,繼承,多型); 3. 跨平臺(Java虛擬機器實現平臺無關性); 4. 可靠性; 5. 安全性; 6. 支援多執行緒 7. 支援編譯與解釋; 8. 支援網路程式設計 ## 1.5 JDK,JRE,JVM之間的區別 **JDK**: java開發工具包;包含JRE, javac等調優診斷工具;能夠建立和編譯程式; **JRE**: java執行環境; 包括 Java 虛擬機器(JVM),Java 類庫,java 命令和其他的一些基礎構件;不能建立程式; **JVM**:java虛擬機器,提供執行位元組碼檔案(.class)的環境支援; > jdk 包含jre ; jre 包含 jvm ## 1.6 面向物件五大基本原則 - 單一職責原則SRP(Single Responsibility Principle);設計類時要功能單一; - 開放封閉原則OCP(Open-Close Principle);一個模組對於拓展是開放的,對於修改是封閉; - 裡式替換原則LSP(the Liskov Substitution Principle LSP);子類可以替換父類; - 依賴倒置原則DIP(the Dependency Inversion Principle DIP);高層次的模組不應該依賴於低層次的模組,他們都應該依賴於抽象。抽象不應該依賴於具體實現,具體實現應該依賴於抽象; - 介面分離原則ISP(the Interface Segregation Principle ISP);設計類時,功能介面拆分為多個; > 開發設計類時需考慮的事情,面試中如果碰見能答幾個就幾個; ## 1.7 什麼是java主類 java主類是java程式碼執行的入口,即包含 main方法的類; ## 1.8 構造器能否被重寫 子類無法繼承父類的構造器,所以構造器不能被重寫(overidde),但可以被過載(overload); ## 1.9 過載和重寫的區別 `重寫 `: - 發生在父類與子類之間 - 方法名,引數列表,必須相同,返回值小於等於父類; - 訪問修飾符大於等於父類(public>protected>default>private);父類方法為private,則無法重寫; - 重丟擲異常的範圍要小於等於父類異常; `過載`: - 發生在同一個類中 - 方法名相同引數列表不同(引數型別不同、個數不同、順序不同); - 方法返回值和訪問修飾符可以不同; ## 1.10 equals與==的區別 **==** : 判定是否是相同一個物件 ,比較的是變數(棧)記憶體中存放的物件的(堆)記憶體地址,用來判斷兩個物件的地址是否相同,; **equals**: equals用來比較的是兩個物件的內容是否相等; **但Object中的equals方法返回的卻是==的判斷**; ## 1.11什麼是hashCode hashCode() 的作用是獲取雜湊碼,也稱為雜湊碼;它實際上一個int整數;雜湊碼的作用是確定該物件在雜湊表中的索引位置;散列表儲存的是鍵值對(key-value),即能根據鍵獲取值; 當一個物件插入散列表時先會比較物件與散列表中已有的物件hash值,若不同,則直接插入散列表,若相同(hash碰撞),則會呼叫equals 方法檢查是否真的相同, 如果equal()判斷不相等,直接將該元素放入集合中,否則不放入; **物件中hashCode()與equals()的關係** - 如果兩個物件相等,則hashcode也相等; - 兩個物件相等,對兩個物件分別呼叫equals方法都返回true - 兩個物件有相同的hashcode值,它們不一定是同一個物件; - equals 方法被覆蓋過,則 hashCode 方法也必須被覆蓋; ## 1.12 什麼是值傳遞和引用傳遞 **值傳遞**:傳遞了物件的一個副本,即使副本被改變,也不會影響源物件; **引用傳遞**:著傳遞的並不是實際的物件,而是物件的引用;對外部物件的改變會反映到實際物件; > 一般認為,Java 內的傳遞都是值傳遞,Java 中例項物件的傳遞是引用傳遞; ## 1.13 什麼是抽象類與介面 - 抽象類是對類的抽象,是一種模板設計; 而介面是行為的抽象,可以理解為行為的規範; - 抽象類中可以包含非抽象方法;而介面是絕對的抽象方法; - 介面預設是public 方法,java8中介面支援預設(default)方法; - 一個類可以實現多個介面,但只能實現一個抽象類; - 抽象類不能使用final修飾(final修飾的類為固定類,無法被繼承) ## 1.14String、String StringBuffer 和 StringBuilder 的區別 - String是隻讀字串,並不是基本資料型別,而是一個物件;其無法改變;每次操作都會產生新物件; - StringBuilder 並沒有對方法進行加同步鎖,執行緒不安全; - StringBuffer 對方法加了同步鎖,執行緒安全; > tip: 資料量少的時候使用 String; 單執行緒使用StringBuilder ; 多執行緒使用 StringBuffer ; 使用StringBuilder 效能比 StringBuffer 效能 提升大概有 10%~15%; ## 1.15 用最有效率的方法計算 2 乘以 8 2 << 3 = 8 ; 2 左移3位 ## 1.16 & 與 && 的區別 & 運算子 按位與; && 運算子是短路與:&& 左邊的表示式的值是 false,右邊的表示式會被直接短路掉,不會進行運算 ## 1.17 static 關鍵字 static 變數在 Java 中屬於類的,它在所有的例項中具有相同的值。當類被 Java 虛擬機器載入的時候,會對 static 變數進行初始化;故需要用例項來訪問 static 變數; ## 1.18 Java 支援的資料型別 1. 整數值型:byte,short,int,long; 2. 字元型:char; 3. 浮點型別:float,double; 4. 布林型:boolean; | 型別 | 位數 | 位元組數 | | :----- | :--- | :----- | | short | 2 | 16 | | int | 4 | 32 | | long | 8 | 64 | | float | 4 | 32 | | double | 8 | 64 | | char | 2 | 16 | ## 1.19 final, finally, finalize 的區別 - final:用於宣告屬性,方法和類, 分別表示屬性不可變, 方法不可覆蓋, 類不可繼承. - finally:異常處理語句結構的一部分,表示最後總是會執行. - finalize:Object類的一個方法,在垃圾收集器執行的時候會呼叫被回收物件的此方法; ## 1.20 instanceof 關鍵字 instanceof 嚴格來說是Java中的一個雙目運算子,用來檢查一個物件是否為一個類的例項; ## 1.21 為什麼不能用浮點型表示金額 浮點數為非精確值,應該使用BigDecimal來修飾金額; ## 1.22 自動裝箱與拆箱 - 裝箱:自動將基本資料型別轉換為包裝器型別,呼叫 Integer的valueOf(int) 方法; - 拆箱:自動將包裝器型別轉換為基本資料型別。呼叫Integer的intValue方法 > tip: int 是基礎資料型別,佔用空間小; Integer 是物件佔用空間大; ## 1.23 switch中能否使用string做引數 在idk 1.7之前,switch只能支援byte, short, char, int或者其對應的封裝類以及Enum型別。從idk 1.7之後switch開始支援String。 > 可以用在byte上,但是不能用在long上。 ## 1.24 java 建立物件的幾種方式 1. 採用new 2. 通過反射 3. 採用clone 4. 通過序列化機制 ## 1.25 如何將byte轉為String 可以使用 String 接收 byte[] 引數的構造器來進行轉換, 但編碼必須正確; ## 1.26 final有哪些用法 1.被final修飾的類不可以被繼承 2.被final修飾的方法不可以被重寫 3.被final修飾的變數不可以被改變。 5.被final修飾的常量,在編譯階段會存入常量池中。 ## 1.27 java當中的四種引用 1. 強引用:如果一個物件具有強引用,它就不會被垃圾回收器回收。即使當前記憶體空間不足,JVM也不會回收它,而是丟擲 OutOfMemoryError 錯誤,使程式異常終止。如果想中斷強引用和某個物件之間的關聯,可以顯式地將引用賦值為null,這樣一來的話,JVM在合適的時間就會回收該物件。 2. 軟引用:在使用軟引用時,如果記憶體的空間足夠,軟引用就能繼續被使用,而不會被垃圾回收器回收,只有在記憶體不足時,軟引用才會被垃圾回收器回收。 3. 弱引用:具有弱引用的物件擁有的生命週期更短暫。因為當 JVM 進行垃圾回收,一旦發現弱引用物件,無論當前記憶體空間是否充足,都會將弱引用回收。 4. 虛引用:如果一個物件僅持有虛引用,那麼它相當於沒有引用,在任何時候都可能被垃圾回收器回收。 ## 1.28 Math. round(-1. 5) 等於多少? Math.round(-1.5)的返回值是-1。四捨五入的原理是在引數上加0.5然後做向下取整 ## 1.29 String str="i"與 String str=new String("i")一樣嗎? tring str="i"的方式,Java 虛擬機器會將其分配到常量池中;而 String str=new String("i") 則會被分到堆記憶體中;所以一個是常量,一個是物件,不一樣; ## 1.30char 型變數中能不能儲存一箇中文漢字 char 型別可以儲存一箇中文漢字,因為 Java 中使用的編碼是 Unicode,一個 char 型別佔 2 個位元組,所以能放一箇中文。 ## 1.31 break 和 continue 的區別 - break 跳出整個迴圈。 - continue 用於跳過本次迴圈,執行下次迴圈。 ## 1.32 內部類與靜態內部類的區別 **內部類:** 1、內部類中的變數和方法不能宣告為靜態。 2、內部類例項化:B是A的內部類,例項化B:`A.B b = new A().new B()`。 3、內部類可以引用外部類的靜態或者非靜態屬性及方法。 **靜態內部類:** 1、靜態內部類屬性和方法可以宣告為靜態的或者非靜態的。 2、例項化靜態內部類:B是A的靜態內部類,`A.B b = new A.B()`。 3、靜態內部類只能引用外部類的靜態的屬性及方法。 ## 1.33 throw和throws的區別? - throw用於主動丟擲java.lang.Throwable 類的一個例項化物件,即通過關鍵字 throw 丟擲一個 Error 或者 一個Exception; - throws 的作用是作為方法宣告和簽名的一部分; ## 1.34 error和exception的區別 - Error類和Exception類的父類都是throwable類 - Error類一般是指與虛擬機器相關的問題,如系統崩潰,虛擬機器錯誤,記憶體空間不足,方法呼叫棧溢等。直接終止程式即可; - Exception類表示程式可以處理的異常,可以捕獲和有可能恢復。需要程式設計師手動處理; ## 1.35 什麼時候用斷言(assert) 斷言是一個包含布林表示式的語句,在執行這個語句時假定該表示式為true;如果表示式的值為false,那麼系統會報告一個AssertionError。 斷言有兩種形式: - `assert Expression1`;表示一個boolean表示式 - `assert Expression1 : Expression2`; Expression2表示一個基本型別、表示式或者是一個Object,用於在失敗時輸出錯誤資訊 ``` assert false; assert i == 0:"123";// 當 i不等於0 時會輸出錯誤資訊 ``` ## 1.36 常見的五種執行時異常 - ClassCastException(類轉換異常) - IndexOutOfBoundsException(陣列越界) - NullPointerException(空指標異常) - ArrayStoreException(資料儲存異常,運算元組是型別不一致) - BufferOverflowException(快取溢位異常) # 二 IO流面試 ## 2.1 序列化的含義 - 序列化:將物件寫入到IO流中 - 反序列化:從IO流中恢復物件 **序列化機制將序列化的Java物件轉換為位位元組序列,這些位元組序列可以儲存在磁碟上,或通過網路傳輸,以達到以後恢復成原來的物件,通常被序列化的要實現Serializable介面,並指定序列值** > Externalizable 可以控制整個序列化過程,指定特定的二進位制格式,增加安全機制 ## 2.2 java 中 IO 流分類 - 按照流的流向分,可以分為輸入流和輸出流; - 按照操作單元劃分,可以劃分為位元組流和字元流; - 按照流的角色劃,可以分為節點流和處理流。 - InputStream/Reader: 所有的輸入流的基類,前者是位元組輸入流,後者是字元輸入流。 - OutputStream/Writer: 所有輸出流的基類,前者是位元組輸出流,後者是字元輸出流。 圖片來源網路: ![](https://gitee.com/lsc180/images/raw/master/img/20200726005822.png) ## 2.3 BIO、NIO、AIO的區別 1. BIO 就是傳統的 `java.io` 包,它是基於流模型實現的,互動的方式是同步、**阻塞方式IO**; 在讀入輸入流或者輸出流時,在讀寫完成之前,執行緒會一直處於阻塞狀態。 2. NIO (New IO)是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以構建多路複用的、同步非阻塞 IO 程式。 3. AIO(Asynchronous IO) 是 Java 1.7 之後引入的包,是 NIO 的升級版本,提供了非同步非堵塞的 IO 操作方式,所以人們叫它 AIO,非同步 IO 是基於事件和回撥機制實現。 # 三 集合面試 ## 3.1 java 集合架構 ![](https://gitee.com/lsc180/images/raw/master/img/collection.jpg) ## 3.2 Collection 和 Collections的區別 Collection:是java.uitl 下的介面,他是各種集合的父介面; Conllecitons:是個java.util下的類,是針對集合的工具類,提供一系列靜態方法對集合的搜尋、查詢、同步等操作; ## 3.3 ArrayList和Vector的區別 - 共同點:都實現了List介面,為有序的集合,底層基於陣列實現,通過索引取值,允許元素重複和為null;都是實現 fail-fast機制; - 區別:ArrayList不同步,Vector是同步(ArrayList 比 Vector 快,不會過載);Vector擴容原來的一倍,ArrayList擴容原來的0.5倍; ## 3.4List,Set,Map 三者的區別? - `List`: 儲存的元素有序可重複。 - `Set`: 儲存的元素是無序的、不可重複的。 - `Map`: 使用鍵值對(kye-value)儲存,通過key 獲取value; key 不能重複; ## 3.5 ArrayList,LinkedList區別 共同點: `ArrayList` 和 `LinkedList` 都是執行緒不安全; 區別: - ArrayList的底層是陣列實現,LinkedList的底層是雙向連結串列實現。 - ArrayList 通過索引獲取值,查詢快;LinkedList通過遍歷連結串列獲取值查詢慢; - ArrayList 增刪慢,LinkedList 增刪快; ## 3.6Enumeration和iterator介面的區別 - iterator是Enumeration介面的替代品,只提供了遍歷vector和HashTable型別集合元素的功能; - Enumeration速度是iterator的2倍,同時佔用更少的記憶體。 - terator有fail-fast機制,比Enumeration更安全 - Iterator能夠刪除元素,Enumeration並不能刪除元素 ## 3.7 簡述Iterator 迭代器 Iterator迭代器可以對集合進行遍歷, 遍歷方式都是 `hasNext()`和`next()`方法,,在當前遍歷集合元素被更改的時候,就會丟擲 `ConcurrentModificationException` 異常; ## 3.8 HashMap和Hashtable的區別 共同點: 都實現 Map介面; 區別: - HashMap不同步;Hashtable同步;HashMap效率比Hashtable高; - HashMap允許為null ;Hashtable不允許為null - Hashtable 預設的初始大小為 11,之後每次擴充,容量變為原來的 2n+1,HashMap 預設的初始化大小為 16; - HashMap 在 jdk1.8 改變了資料結構為 陣列 + 連結串列 + 紅黑樹方式; HashTable使用全表鎖,效率低下; ## 3.9HashSet 和 HashMap 的區別 - HashMap 實現了Map介面;HashSet實現了Set介面 - HashMap儲存鍵值對;HashSet僅僅儲存物件 - HashMap使用put()方法將元素放入map中;HashSet使用add()方法將元素放入set中; - HashMap中使用鍵物件來計算hashcode值;ashSet使用成員物件來計算hashcode值; - HashSet較HashMap來說比較慢; ## 3.10 HashMap和TreeMap區別 TreeMap實現SortMap介面,能夠將記錄根據鍵排序(預設升序排序),也可以指定排序的比較器Comparator,當用Iterator 遍歷TreeMap時得到排序後的結果; > 對於插入、刪除和定位元素等操作,選擇HashMap;如果對一個有序的key集合進行遍歷,選擇TreeMap ## 3.11 併發集合和普通集合區別 併發集合常見的有 `ConcurrentHashMap`、`ConcurrentLinkedQueue`、`ConcurrentLinkedDeque` 等。併發集合位於 java.util.concurrent 包下,是 jdk1.5 之後才有;其相比與普通集合添加了 synchronized 同步鎖,執行緒安全,但效率低; ## 3.12 ConcurrentHashMap1.7和1.8的區別 jdk1.8的實現不再使用jdk1.7的Segment\+ HashEntry分段鎖機制實現,利用`Node陣列`+`CAS+Synchronized`來保證執行緒安全;底層採用`陣列+連結串列+紅黑樹`的儲存結構; ConcurrentHashMap1.7 ![](https://gitee.com/lsc180/images/raw/master/img/20200726102407.png)dk1.7 ConcurrentHashMap1.8 ![](https://gitee.com/lsc180/images/raw/master/img/20200726102754.png) ## 3.13HashMap 的長度為什麼是2的冪次方 目的是為了能讓 HashMap 存取高效,儘量減少Hash碰撞,儘量使Hash演算法的結果均勻分佈,每個連結串列/紅黑樹長度大致相同; 演算法實際是取模,hash%length,計算機中求餘效率不如位移運算,原始碼中做了優化hash&(length-1); hash%length==hash&(length-1)的前提是length是2的n次方 ## 3.14 ArrayList集合如何高效加入10萬條資料 直接在初始化的時候就指定ArrayList的容量值; ## 3.15 如何選用集合 根據集合的特點來選用集合;根據鍵獲取值選用 `Map` 介面下的集合;需要排序選擇 `TreeMap`,不需要排序選擇 `HashMap`,需要執行緒安全選 `ConcurrentHashMap`。 只存放元素值時,就選擇實現`Collection` 介面的集合;需要元素唯一時選擇實現 `Set` 介面的集合,如TreeSet` 或 `HashSet; 不需要元素唯一性就選擇實現 List 介面,如 `ArrayList` 或 `LinkedList`; ## 3.16 快速失敗(fail-fast)和安全失敗(fail-safe)的區別是什麼 - 快速失敗:當你在迭代一個集合的時候,如果有另一個執行緒正在修改你正在訪問的那個集合時,就會丟擲一個 ConcurrentModification 異常。 在 java.util 包下的都是快速失敗。 - 安全失敗:你在迭代的時候會去底層集合做一個拷貝,所以你在修改上層集合的時候是不會受影響的,不會丟擲 ConcurrentModification 異常。在java.util.concurrent 包下的全是安全失敗的。 附: HashMap 原始碼分析: https://blog.csdn.net/youku1327/article/details/105332136; ArrayList原始碼分析https://blog.csdn.net/youku1327/article/details/105314040 > tip: 需要懂 HashMap,ArrayList,LinkedList,ConcurrentHashMap底層實