江蘇省建設(shè)招標(biāo)網(wǎng)站首頁阿里云域名查詢和注冊
本篇總結(jié)的是Java基礎(chǔ)知識相關(guān)的面試題,后續(xù)也會更新其他相關(guān)內(nèi)容
文章目錄
- 1、== 和 equals 的區(qū)別是什么?
- 2、你重寫過 hashcode 和 equals 嗎,為什么重寫equals時必須重寫hashCode方法?
- 3、為什么Java中只有值傳遞?
- 4、BIO、NIO、AIO 有什么區(qū)別?
- 5、什么是反射機(jī)制?反射機(jī)制的應(yīng)用場景有哪些?
- 6、String有哪些特性?
- 7、String和StringBuffer、StringBuilder的區(qū)別是什么?String 為什么是不可變的?
- 8、集合和數(shù)組的區(qū)別是什么?
- 9、List,Set,Map三者的區(qū)別?
- 10、在使用 HashMap 的時候,用 String 做 key 有什么好處?
1、== 和 equals 的區(qū)別是什么?
答:
- ==:它的作用是判斷兩個對象的地址是不是相等。即,判斷兩個對象是不是同一個對象。(基本數(shù)據(jù)類型比較的是值,引用數(shù)據(jù)類型比較的是內(nèi)存地址)
- equals:它的作用也是判斷兩個對象是否相等。但它一般有兩種使用情況:
- 情況1:類沒有覆蓋equals() 方法。則通過 equals() 比較該類的兩個對象時, 等價于通過“==”比較這兩個對象。
- 情況2:類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來比較兩個對象的內(nèi)容是否相等;若它們的內(nèi)容相等,則返回 true (即,認(rèn)為這兩個對象相等)。
String中的equals方法是被重寫過的,因為object的equals方法是比較的對象的內(nèi)存地址,而String的equals方法比較的是對象的值。
當(dāng)創(chuàng)建String類型的對象時,虛擬機(jī)會在常量池中查找有沒有已經(jīng)存在的值和要創(chuàng)建的值相同的對象,如果有就把它賦給當(dāng)前引用。如果沒有就在常量池中重新創(chuàng)建一個String對象。
2、你重寫過 hashcode 和 equals 嗎,為什么重寫equals時必須重寫hashCode方法?
答:如果我們只重寫了equals方法沒有重寫hashcode方法的時候,就可能會導(dǎo)致兩個對象通過equals方法比較之后判斷相等,而兩個對象的hashcode不同,因為它們的引用地址是不同的。
但是這時候就違背了hashcode 的規(guī)則:兩個對象相等其 hash 值一定要相等,這樣就會導(dǎo)致我們在使用hashcode計算存儲地址的時候,兩個相同的對象卻存儲在不同的位置,這顯然是不合理的。所以我們在重寫equals時,必須要重寫hashCode方法。
如下:
public class Main {public static void main(String[] args) {// 對象 1Persion p1 = new Persion();p1.setName("Java");p1.setAge(18);// 對象 2Persion p2 = new Persion();p2.setName("Java");p2.setAge(18);// 創(chuàng)建 Set 對象Set<Persion> set = new HashSet<Persion>();set.add(p1);set.add(p2);// 打印 Set 中的所有數(shù)據(jù)set.forEach(p -> {System.out.println(p);});}
}class Persion {private String name;private int age;@Overridepublic boolean equals(Object o) {if (this == o) return true; // 引用相等返回 true// 如果等于 null,或者對象類型不同返回 falseif (o == null || getClass() != o.getClass()) return false;// 強轉(zhuǎn)為自定義 Persion 類型Persion persion = (Persion) o;// 如果 age 和 name 都相等,就返回 truereturn age == persion.age &&Objects.equals(name, persion.name);}@Overridepublic int hashCode() {// 對比 name 和 age 是否相等return Objects.hash(name, age);}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Persion{" +"name='" + name + '\'' +", age=" + age +'}';}
}
如果你還不理解可以看這篇:文章
3、為什么Java中只有值傳遞?
答:當(dāng)方法參數(shù)是基本數(shù)據(jù)類型時,我們進(jìn)行參數(shù)傳遞的時候就是將這個基本數(shù)據(jù)類型復(fù)制一份然后作為參數(shù)傳遞。當(dāng)方法參數(shù)是引用類型時,我們進(jìn)行參數(shù)傳遞的時候就是將這個引用復(fù)制一份然后作為參數(shù)傳遞。
4、BIO、NIO、AIO 有什么區(qū)別?
答:
- BIO:
Block IO
同步阻塞式 IO,就是我們平常使用的傳統(tǒng) IO,它的特點是模式簡單使用方便,并發(fā)處理能力低。 - NIO:
Non IO
同步非阻塞 IO,是傳統(tǒng) IO 的升級,客戶端和服務(wù)器端通過
Channel(通道)通訊,實現(xiàn)了多路復(fù)用。 - AIO:
Asynchronous IO
是 NIO 的升級,也叫 NIO2,實現(xiàn)了異步非堵塞 IO
,異步 IO 的操作基于事件和回調(diào)機(jī)制。
5、什么是反射機(jī)制?反射機(jī)制的應(yīng)用場景有哪些?
答:JAVA反射機(jī)制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制。
- 靜態(tài)編譯:在編譯時確定類型,綁定對象
- 動態(tài)編譯:在運行時確定類型,綁定對象
反射機(jī)制優(yōu)缺點:
優(yōu)點: 運行期類型的判斷,動態(tài)加載類,提高代碼靈活度。
缺點: 性能瓶頸,反射相當(dāng)于一系列解釋操作,通知 JVM 要做的事情,性能比直接的java代碼要慢很多。
反射機(jī)制的應(yīng)用場景:
- ①我們在使用JDBC連接數(shù)據(jù)庫時使用Class.forName()通過反射加載數(shù)據(jù)庫的驅(qū)動程序;
- ②Spring框架也用到很多反射機(jī)制, 經(jīng)典的就是xml的配置模式。Spring 通過 XML 配置模式裝載 Bean
的過程:- 將程序內(nèi)所有 XML 或 Properties 配置文件加載入內(nèi)存中;
- Java類里面解析xml或properties里面的內(nèi)容,得到對應(yīng)實體類的字節(jié)碼字符串以及相關(guān)的屬性信息;
- 使用反射機(jī)制,根據(jù)這個字符串獲得某個類的Class實例;
- 動態(tài)配置實例的屬性;
6、String有哪些特性?
答:
- 不變性:String 是只讀字符串,是一個典型的 immutable 對象,**對它進(jìn)行任何操作,其實都是創(chuàng)
建一個新的對象,再把引用指向該對象。**不變模式的主要作用在于當(dāng)一個對象需要被多線程共享并
頻繁訪問時,可以保證數(shù)據(jù)的一致性。 - 常量池優(yōu)化:String 對象創(chuàng)建之后,會在字符串常量池中進(jìn)行緩存,如果下次創(chuàng)建同樣的對象時,
會直接返回緩存的引用。 - final:使用 final 來定義 String 類,表示 String 類不能被繼承,提高了系統(tǒng)的安全性。
7、String和StringBuffer、StringBuilder的區(qū)別是什么?String 為什么是不可變的?
答:我們分別從可變性、線程安全性和性能三個方面來講:
可變性:
- String類中使用字符數(shù)組保存字符串,
private final char value[]
,但是使用了final關(guān)鍵字來修飾,所以 string對象是不可變的。 - StringBuilder類時繼承自
AbstractStringBuilder
類,在AbstractStringBuilder中也是使用字符數(shù)組保存字符串,char[] value
,StringBuilder對象都是可變的。 - StringBuffer類時繼承自
AbstractStringBuilder
類,在AbstractStringBuilder中也是使用字符數(shù)組保存字符串,char[] value
,StringBuffer對象都是可變的。
線程安全性:
- String中的對象是不可變的,也就可以理解為常量,線程安全。
- StringBuffer對方法加了同步鎖或者對調(diào)用的方法加了同步鎖,所以是線程安全的。
- StringBuilder并沒有對方法進(jìn)行加同步鎖,所以是非線程安全的。
性能:
- String類型:每次對String 類型進(jìn)行改變的時候,都會生成一個新的String對象,然后將指針指向新的String 對象。
- StringBuffer類型:每次都會對StringBuffer對象本身進(jìn)行操作,而不是生成新的對象并改變對象引用,所以性能強于String類型。
- StringBuilder:StringBuilder類型與StringBuffer類型相似,但是由于StringBuilder沒有對方法加鎖,所以性能強于StringBuffer。
使用場景選擇:
- String :要操作少量的數(shù)據(jù)可以選擇String;
- StringBuilder:單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù);
- StringBuffer:多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù);
8、集合和數(shù)組的區(qū)別是什么?
答:
- 數(shù)組是固定長度的;集合可變長度的。
- 數(shù)組可以存儲基本數(shù)據(jù)類型,也可以存儲引用數(shù)據(jù)類型;集合只能存儲引用數(shù)據(jù)類型。
- 數(shù)組存儲的元素必須是同一個數(shù)據(jù)類型;集合存儲的對象可以是不同數(shù)據(jù)類型。
9、List,Set,Map三者的區(qū)別?
答:Java 容器分為 Collection 和 Map 兩大類,Collection集合的子接口有Set、 List、Queue三種子接口。
我們比較常用的是Set、List,Map接口不是 collection的子接口。
如下圖:
圖片來源:Java集合中List,Set以及Map等集合體系詳解(史上最全)
Collection集合主要有List和Set兩大接口:
- List:一個有序(元素存入集合的順序和取出的順序一致)容器,元素可以重復(fù),可以插入多個
null元素,元素都有索引。 - Set:一個無序(存入和取出順序有可能不一致)容器,不可以存儲重復(fù)元素, 只允許存入一個
null元素,必須保證元素唯一性。 - Map是一個鍵值對集合,存儲鍵、值和之間的映射。 Key無序,唯一;value 不要求有序,允許重復(fù)。Map沒有繼承于Collection接口,從Map集合中檢索元素時,只要給出鍵對象,就會返回對應(yīng)的值對象。
List接口常用的實現(xiàn)類有
ArrayList
、LinkedList
和Vector
。
Set接口常用的實現(xiàn)類有HashSet
、LinkedHashSet
以及TreeSet
。
Map接口常用的實現(xiàn)類:HashMap
、TreeMap
、HashTable
、LinkedHashMap
、ConcurrentHashMap
。
10、在使用 HashMap 的時候,用 String 做 key 有什么好處?
答:HashMap 內(nèi)部實現(xiàn)是通過 key 的 hashcode 來確定 value 的存儲位置,因為字符串是不可變的,所以
當(dāng)創(chuàng)建字符串時,它的 hashcode 被緩存下來,不需要再次計算它的hashcode,所以相比于其他對象更快。