今天天津卓眾教育java培訓(xùn)機(jī)構(gòu)小編為大家分享“最常見的208道Java最新面試題及答案”,本文主要包含十九個(gè)模塊的java面試題,分別是:Java 基礎(chǔ)、容器、多線程、反射、對象拷貝、Java Web 、異常、網(wǎng)絡(luò)、設(shè)計(jì)模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM,希望通過此能夠幫助到正在找工作或是準(zhǔn)備找工作的“你”,下面就隨小編一起看看。
java面試題模塊
一、 java最新面試題及答案:Java基礎(chǔ)模塊
1、JDK 和 JRE 有什么區(qū)別?
JDK:Java Development Kit 的簡稱,Java 開發(fā)工具包,提供了 Java 的開發(fā)環(huán)境和運(yùn)行環(huán)境。
JRE:Java Runtime Environment 的簡稱,Java 運(yùn)行環(huán)境,為 Java 的運(yùn)行提供了所需環(huán)境。
具體來說 JDK 其實(shí)包含了 JRE,同時(shí)還包含了編譯 Java 源碼的編譯器 Javac,還包含了很多 Java 程序調(diào)試和分析的工具。簡單來說:如果你需要運(yùn)行 Java 程序,只需安裝 JRE 就可以了,如果你需要編寫 Java 程序,需要安裝 JDK。
2、== 和 equals 的區(qū)別是什么?
== 解讀:
對于基本類型和引用類型 == 的作用效果是不同的,如下所示:
基本類型:比較的是值是否相同;
引用類型:比較的是引用是否相同;
代碼示例:
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
代碼解讀:因?yàn)?x 和 y 指向的是同一個(gè)引用,所以 == 也是 true,而 new String()方法則重寫開辟了內(nèi)存空間,所以 == 結(jié)果為 false,而 equals 比較的一直是值,所以結(jié)果都為 true。
equals 解讀:
equals 本質(zhì)上就是 ==,只不過 String 和 Integer 等重寫了 equals 方法,把它變成了值比較??聪旅娴拇a就明白了。
首先來看默認(rèn)情況下 equals 比較一個(gè)有相同值的對象,代碼如下:
class Cat {
public Cat(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Cat c1 = new Cat;
Cat c2 = new Cat;
System.out.println(c1.equals(c2)); // false
輸出結(jié)果出乎我們的意料,竟然是 false?這是怎么回事,看了 equals 源碼就知道了,源碼如下:
public boolean equals(Object obj) {
return (this == obj);
}
原來 equals 本質(zhì)上就是 ==。
同樣的,當(dāng)我們進(jìn)入 String 的 equals 方法,找到了答案,代碼如下:
String s1 = new String;
String s2 = new String;
System.out.println(s1.equals(s2)); // true
同樣的,當(dāng)我們進(jìn)入 String 的 equals 方法,找到了答案,代碼如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
原來是 String 重寫了 Object 的 equals 方法,把引用比較改成了值比較。
總結(jié) :== 對于基本類型來說是值比較,對于引用類型來說是比較的是引用;而 equals 默認(rèn)情況下是引用比較,只是很多類重新了 equals 方法,比如 String、Integer 等把它變成了值比較,所以一般情況下 equals 比較的是值是否相等。
3、兩個(gè)對象的 hashCode() 相同,則 equals() 也一定為 true,對嗎?
不對,兩個(gè)對象的 hashCode() 相同,equals() 不一定 true。
代碼示例:
String str1 = "精彩";
String str2 = "筆記";
System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));
代碼解讀:很顯然“精彩”和“筆記”的 hashCode() 相同,然而 equals() 則為 false,因?yàn)樵谏⒘斜碇校琱ashCode() 相等即兩個(gè)鍵值對的哈希值相等,然而哈希值相等,并不一定能得出鍵值對相等。
4、final 在 Java 中有什么作用?
final 修飾的類叫最終類,該類不能被繼承。
final 修飾的方法不能被重寫。
final 修飾的變量叫常量,常量必須初始化,初始化之后值就不能被修改。
5、Java 中的 Math. round(-1. 5) 等于多少?
等于 -1。round()是四舍五入,注意負(fù)數(shù)5是舍的,例如:Math.round(1.5)值是2,Math.round(-1.5)值是-1。
6、String 屬于基礎(chǔ)的數(shù)據(jù)類型嗎?
String 不屬于基礎(chǔ)類型,基礎(chǔ)類型有 8 種:byte、boolean、char、short、int、float、long、double,而 String 屬于對象。
7、Java 中操作字符串都有哪些類?它們之間有什么區(qū)別?
操作字符串的類有:String、StringBuffer、StringBuilder。
三者區(qū)別:
StringBuffer和StringBuilder都繼承自抽象類AbstractStringBuilder。
String 聲明的是不可變的對象,每次操作都會生成新的 String 對象,然后將指針指向新的 String 對象,而 StringBuffer、StringBuilder 存儲數(shù)據(jù)的字符數(shù)組沒有被final修飾,說明值可以改變,抽象類AbstractStringBuilder內(nèi)部都提供了一個(gè)自動擴(kuò)容機(jī)制,當(dāng)發(fā)現(xiàn)長度不夠的時(shí)候(初始默認(rèn)長度是16),會自動進(jìn)行擴(kuò)容工作,擴(kuò)展為原數(shù)組長度的2倍加2,創(chuàng)建一個(gè)新的數(shù)組,并將數(shù)組的數(shù)據(jù)復(fù)制到新數(shù)組,所以對于拼接字符串效率要比String要高。
線程安全性:StringBuffer由于很多方法都被 synchronized 修飾了所以線程安全,但是當(dāng)多線程訪問時(shí),加鎖和釋放鎖的過程很平凡,所以效率相比StringBuilder要低。StringBuilder相反執(zhí)行效率高,但是線程不安全。所以單線程環(huán)境下推薦使用 StringBuilder,多線程環(huán)境下推薦使用 StringBuffer。
執(zhí)行速度:StringBuilder > StringBuffer > String。
8、String str="i"與 String str=new String(“i”)一樣嗎?
不一樣,因?yàn)閮?nèi)存的分配方式不一樣。String str=“i"的方式,Java 虛擬機(jī)會將其分配到常量池中,如果常量池中有"i”,就返回"i"的地址,如果沒有就創(chuàng)建"i",然后返回"i"的地址;而 String str=new String(“i”) 則會被分到堆內(nèi)存中新開辟一塊空間。
9、如何將字符串反轉(zhuǎn)?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
示例代碼:
// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba
10、String 類的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引處的字符。
replace():字符串替換。
trim():去除字符串兩端空白。
split():分割字符串,返回一個(gè)分割后的字符串?dāng)?shù)組。
getBytes():返回字符串的 byte 類型數(shù)組。
length():返回字符串長度。
toLowerCase():將字符串轉(zhuǎn)成小寫字母。
toUpperCase():將字符串轉(zhuǎn)成大寫字符。
substring():截取字符串。
equals():字符串比較。
11、抽象類必須要有抽象方法嗎?
不需要,抽象類不一定非要有抽象方法;但是包含一個(gè)抽象方法的類一定是抽象類。
示例代碼:
abstract class Cat {
public static void sayHi() {
System. out. println("hi~");
}
}
上面代碼,抽象類并沒有抽象方法但完全可以正常運(yùn)行。
12、普通類和抽象類有哪些區(qū)別?
普通類不能包含抽象方法,抽象類可以包含抽象方法。
抽象類是不能被實(shí)例化的,就是不能用new調(diào)出構(gòu)造方法創(chuàng)建對象,普通類可以直接實(shí)例化。
如果一個(gè)類繼承于抽象類,則該子類必須實(shí)現(xiàn)父類的抽象方法。如果子類沒有實(shí)現(xiàn)父類的抽象方法,則必須將子類也定義為abstract類。
13、抽象類能使用 final 修飾嗎?
不能,定義抽象類就是讓其他類繼承的,如果定義為 final 該類就不能被繼承,這樣彼此就會產(chǎn)生矛盾,所以 final 不能修飾抽象類,如下圖所示,編輯器也會提示錯(cuò)誤信息:
14、接口和抽象類有什么區(qū)別?
實(shí)現(xiàn):抽象類的子類使用 extends 來繼承;接口必須使用 implements 來實(shí)現(xiàn)接口。
構(gòu)造函數(shù):抽象類可以有構(gòu)造函數(shù);接口不能有。
實(shí)現(xiàn)數(shù)量:類可以實(shí)現(xiàn)很多個(gè)接口;但只能繼承一個(gè)抽象類【java只支持單繼承】。
訪問修飾符:接口中的方法默認(rèn)使用 public 修飾;抽象類中的抽象方法可以使用Public和Protected修飾,如果抽象方法修飾符為Private,則報(bào)錯(cuò):The abstract method 方法名 in type Test can only set a visibility modifier, one of public or protected。
15、Java 中 IO 流分為幾種?
按功能來分:輸入流(input)、輸出流(output)。
按類型來分:字節(jié)流和字符流。
字節(jié)流和字符流的區(qū)別是:字節(jié)流按 8 位傳輸以字節(jié)為單位輸入輸出數(shù)據(jù),字符流按 16 位傳輸以字符為單位輸入輸出數(shù)據(jù)。
16、BIO、NIO、AIO 有什么區(qū)別?
BIO:Block IO 同步阻塞式 IO,就是我們平常使用的傳統(tǒng) IO,它的特點(diǎn)是模式簡單使用方便,并發(fā)處理能力低。
NIO:New IO 同步非阻塞 IO,是傳統(tǒng) IO 的升級,客戶端和服務(wù)器端通過 Channel(通道)通訊,實(shí)現(xiàn)了多路復(fù)用。
AIO:Asynchronous IO 是 NIO 的升級,也叫 NIO2,實(shí)現(xiàn)了異步非堵塞 IO ,異步 IO 的操作基于事件和回調(diào)機(jī)制。
17、Files的常用方法都有哪些?
Files. exists():檢測文件路徑是否存在。
Files. createFile():創(chuàng)建文件。
Files. createDirectory():創(chuàng)建文件夾。
Files. delete():刪除一個(gè)文件或目錄。
Files. copy():復(fù)制文件。
Files. move():移動文件。
Files. size():查看文件個(gè)數(shù)。
Files. read():讀取文件。
Files. write():寫入文件。
二、java最新面試題及答案:Java 容器模塊
18、Java 容器都有哪些?
Java 容器分為 Collection 和 Map 兩大類,其下又有很多子類,如下所示:
Collection
List
ArrayList
linkedList
Vector
Stack
Set
HashSet
linkedHashSet
TreeSet
Map
HashMap
linkedHashMap
TreeMap
ConcurrentHashMap
Hashtable
19、Collection 和 Collections 有什么區(qū)別?
Collection 是一個(gè)集合接口,它提供了對集合對象進(jìn)行基本操作的通用接口方法,所有集合都是它的子類,比如 List、Set 等。
Collections 是一個(gè)包裝類,包含了很多靜態(tài)方法,不能被實(shí)例化,就像一個(gè)工具類,比如提供的排序方法:Collections. sort(list)。
20、List、Set、Map 之間的區(qū)別是什么?
List、Set、Map 的區(qū)別主要體現(xiàn)在兩個(gè)方面:元素是否有序、是否允許元素重復(fù)。
三者之間的區(qū)別,如下表:
21、HashMap 和 Hashtable 有什么區(qū)別?
HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類。不過它們都實(shí)現(xiàn)了同時(shí)實(shí)現(xiàn)了map、Cloneable(可復(fù)制)、Serializable(可序列化)這三個(gè)接口。
Hashtable比HashMap多提供了elments() 和contains() 兩個(gè)方法。
HashMap的key-value支持key-value,null-null,key-null,null-value四種。而Hashtable只支持key-value一種(即key和value都不為null這種形式)。既然HashMap支持帶有null的形式,那么在HashMap中不能由get()方法來判斷HashMap中是否存在某個(gè)鍵, 而應(yīng)該用containsKey()方法來判斷,因?yàn)槭褂胓et的時(shí)候,當(dāng)返回null時(shí),你無法判斷到底是不存在這個(gè)key,還是這個(gè)key就是null,還是key存在但value是null。
線程安全性不同:HashMap的方法都沒有使用synchronized關(guān)鍵字修飾,都是非線程安全的,而Hashtable的方法幾乎都是被synchronized關(guān)鍵字修飾的。但是,當(dāng)我們需要HashMap是線程安全的時(shí),怎么辦呢?我們可以通過Collections.synchronizedMap(hashMap)來進(jìn)行處理,亦或者我們使用線程安全的ConcurrentHashMap。ConcurrentHashMap雖然也是線程安全的,但是它的效率比Hashtable要高好多倍。因?yàn)镃oncurrentHashMap使用了分段鎖,并不對整個(gè)數(shù)據(jù)進(jìn)行鎖定。
初始容量大小和每次擴(kuò)充容量大小的不同:Hashtable默認(rèn)的初始大小為11,之后每次擴(kuò)充,容量變?yōu)樵瓉淼?n+1。HashMap默認(rèn)的初始化大小為16。之后每次擴(kuò)充,容量變?yōu)樵瓉淼?倍。
計(jì)算hash值的方法不同:為了得到元素的位置,首先需要根據(jù)元素的 KEY計(jì)算出一個(gè)hash值,然后再用這個(gè)hash值來計(jì)算得到最終的位置。Hashtable直接使用對象的hashCode。hashCode是JDK根據(jù)對象的地址或者字符串或者數(shù)字算出來的int類型的數(shù)值。然后再使用除留余數(shù)發(fā)來獲得最終的位置。
22、如何決定使用 HashMap 還是 TreeMap?
對于在 Map 中插入、刪除、定位一個(gè)元素這類操作,HashMap 是最好的選擇,因?yàn)橄鄬Χ?HashMap 的插入會更快,但如果你要對一個(gè) key 集合進(jìn)行有序的遍歷,那 TreeMap 是更好的選擇。
23、說一下 HashMap 的實(shí)現(xiàn)原理?
HashMap 基于 Hash 算法實(shí)現(xiàn)的,我們通過 put(key,value)存儲,get(key)來獲取。當(dāng)傳入 key 時(shí),HashMap 會根據(jù) key. hashCode() 計(jì)算出 hash 值,根據(jù) hash 值將 value 保存在 bucket 里。當(dāng)計(jì)算出的 hash 值相同時(shí),我們稱之為 hash 沖突,HashMap 的做法是用鏈表和紅黑樹存儲相同 hash 值的 value。當(dāng) hash 沖突的個(gè)數(shù)比較少時(shí),使用鏈表否則使用紅黑樹。
24、說一下 HashSet 的實(shí)現(xiàn)原理?
HashSet 是基于 HashMap 實(shí)現(xiàn)的,HashSet 底層使用 HashMap 來保存所有元素,因此 HashSet 的實(shí)現(xiàn)比較簡單,相關(guān) HashSet 的操作,基本上都是直接調(diào)用底層 HashMap 的相關(guān)方法來完成,HashSet 不允許重復(fù)的值。
25、ArrayList 和 linkedList 的區(qū)別是什么?
數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn):ArrayList 是動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),而 linkedList 是雙向鏈表的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)。
隨機(jī)訪問效率:ArrayList 比 linkedList 在隨機(jī)訪問的時(shí)候效率要高,因?yàn)?linkedList 是線性的數(shù)據(jù)存儲方式,所以需要移動指針從前往后依次查找。
增加和刪除效率:在非首尾的增加和刪除操作,linkedList 要比 ArrayList 效率要高,因?yàn)?ArrayList 增刪操作要影響數(shù)組內(nèi)的其他數(shù)據(jù)的下標(biāo)。
綜合來說,在需要頻繁讀取集合中的元素時(shí),更推薦使用 ArrayList,而在插入和刪除操作較多時(shí),更推薦使用 linkedList。
26、如何實(shí)現(xiàn)數(shù)組和 List 之間的轉(zhuǎn)換?
數(shù)組轉(zhuǎn) List:使用 Arrays. asList(array) 進(jìn)行轉(zhuǎn)換。
List 轉(zhuǎn)數(shù)組:使用 List 自帶的 toArray() 方法。
代碼示例:
// list to array
List
list. add;
list. add;
list. toArray();
// array to list
String[] array = new String[];
Arrays. asList(array);
27、ArrayList 和 Vector 的區(qū)別是什么?
線程安全:Vector 使用了 Synchronized 來實(shí)現(xiàn)線程同步,是線程安全的,而 ArrayList 是非線程安全的。
性能:ArrayList 在性能方面要優(yōu)于 Vector。
擴(kuò)容:ArrayList 和 Vector 都會根據(jù)實(shí)際的需要?jiǎng)討B(tài)的調(diào)整容量,只不過在 Vector 擴(kuò)容每次會增加 1 倍,而 ArrayList 只會增加 50%。
28、Array 和 ArrayList 有何區(qū)別?
Array 可以存儲基本數(shù)據(jù)類型和對象,ArrayList 只能存儲對象。
Array 是指定固定大小的,而 ArrayList 大小是自動擴(kuò)展的。
Array 內(nèi)置方法沒有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。
29、在 Queue 中 poll()和 remove()有什么區(qū)別?
相同點(diǎn):都是返回第一個(gè)元素,并在隊(duì)列中刪除返回的對象。
不同點(diǎn):如果沒有元素 remove()會直接拋出NoSuchElementException 異常,而 poll()會返回 null。
代碼示例:
Queue
queue. offer("string"); // add
System. out. println(queue. poll());
System. out. println(queue. remove());
System. out. println(queue. size());
30、哪些集合類是線程安全的?
Vector、Hashtable、Stack 都是線程安全的,而像 HashMap 則是非線程安全的,不過在 JDK 1.5 之后隨著 Java. util. concurrent 并發(fā)包的出現(xiàn),它們也有了自己對應(yīng)的線程安全類,比如 HashMap 對應(yīng)的線程安全類就是 ConcurrentHashMap。
由于“最常見的208道Java最新面試題及答案”內(nèi)容太多,本文已滿,請看下文鏈接:
31~73道Java最新面試題及答案請看鏈接:http://www.bjpowernode.com/javazixun/2145.html
74~124道Java最新面試題及答案請看鏈接:http://www.bjpowernode.com/javazixun/2146.html
125~170道Java最新面試題及答案請看鏈接:http://www.bjpowernode.com/javazixun/2148.html
171~208道Java最新面試題及答案請看鏈接:http://www.bjpowernode.com/javazixun/2149.html