前言

熬夜整理了一份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
assert Expression1 : Expression2
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: 所有輸出流的基類,前者是字節輸出流,後者是字符輸出流。

圖片來源網絡:

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 集合架構

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

3.5 ArrayList,LinkedList區別

共同點:

ArrayListLinkedList 都是線程不安全;

區別:

  • 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 併發集合和普通集合區別

併發集合常見的有 ConcurrentHashMapConcurrentLinkedQueueConcurrentLinkedDeque 等。併發集合位於 java.util.concurrent 包下,是 jdk1.5 之後纔有;其相比與普通集合添加了 synchronized 同步鎖,線程安全,但效率低;

3.12 ConcurrentHashMap1.7和1.8的區別

jdk1.8的實現不再使用jdk1.7的Segment+ HashEntry分段鎖機制實現,利用 Node數組 + CAS+Synchronized 來保證線程安全;底層採用 數組+鏈表+紅黑樹 的存儲結構;

ConcurrentHashMap1.7

dk1.7

ConcurrentHashMap1.8

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 接口,如 ArrayListLinkedList ;

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底層實現原理

相關文章