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