有些問(wèn)題真的挺無(wú)語(yǔ)的,面高級(jí)怎么還在問(wèn)這些
==和equals的區(qū)別, 0.1*5 == 0.5的結(jié)果
==對(duì)于基本類(lèi)型,比較的是值,但對(duì)于引用類(lèi)型,比較的是內(nèi)存地址
equals對(duì)于引用類(lèi)型,首先,equals會(huì)用==比較兩個(gè)類(lèi)型在內(nèi)存中的地址,如果一樣,則直接返回true,如果不一樣,則直接往下走,再判斷是否為string類(lèi)型,如果不是,則強(qiáng)轉(zhuǎn)為string類(lèi)型,再將字符串?dāng)?shù)組拆分為單個(gè)字符,一一比較,有一個(gè)不相同,則返回false,否則返回true
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;
}
從上面可以看出 0.1*5 == 0.5 的結(jié)果應(yīng)該為true,因?yàn)樗麄兪腔緮?shù)據(jù)類(lèi)型,直接比較值

還遇到了另外一個(gè)問(wèn)題,如下圖。

因?yàn)镾tring a = "abc"在編譯的時(shí)候,jvm將abc放入常量池,并在常量池中創(chuàng)建該常量的地址,然后將a去指向這個(gè)常量,當(dāng)我們執(zhí)行String a = "abc"的時(shí)候,會(huì)去常量池中尋找有沒(méi)有abc這個(gè)常量,如果有,則將b指向它,沒(méi)有就創(chuàng)建,所以a和b都指向常量池中的abc,故內(nèi)存地址相同。
而在 String str1 = new String("abc")中,首先會(huì)在堆內(nèi)存中去開(kāi)辟一個(gè)空間去存儲(chǔ)abc,當(dāng)我們?cè)賜ew對(duì)象的時(shí)候,還會(huì)再去開(kāi)辟,所以二則的內(nèi)存地址不相同,故返回false
聚簇索引和非聚簇索引的區(qū)別
- 聚集索引
聚集索引即索引結(jié)構(gòu)和數(shù)據(jù)一起存放的索引。主鍵索引屬于聚集索引。
在 MySQL 中,InnoDB 引擎的表的 .ibd文件就包含了該表的索引和數(shù)據(jù),對(duì)于 InnoDB 引擎表來(lái)說(shuō),該表的索引(B+樹(shù))的每個(gè)非葉子節(jié)點(diǎn)存儲(chǔ)索引,葉子節(jié)點(diǎn)存儲(chǔ)索引和索引對(duì)應(yīng)的數(shù)據(jù)。
聚集索引的優(yōu)點(diǎn):聚集索引的查詢速度非常的快,因?yàn)檎麄€(gè) B+樹(shù)本身就是一顆多叉平衡樹(shù),葉子節(jié)點(diǎn)也都是有序的,定位到索引的節(jié)點(diǎn),就相當(dāng)于定位到了數(shù)據(jù)。
聚集索引的缺點(diǎn):- 依賴(lài)于有序的數(shù)據(jù) :因?yàn)?B+樹(shù)是多路平衡樹(shù),如果索引的數(shù)據(jù)不是有序的,那么就需要在插入時(shí)排序,如果數(shù)據(jù)是整型還好,否則類(lèi)似于字符串或 UUID 這種又長(zhǎng)又難比較的數(shù)據(jù),插入或查找的速度肯定比較慢。
- 更新代價(jià)大:如果對(duì)索引列的數(shù)據(jù)被修改時(shí),那么對(duì)應(yīng)的索引也將會(huì)被修改,而且聚集索引的葉子節(jié)點(diǎn)還存放著數(shù)據(jù),修改代價(jià)肯定是較大的,所以對(duì)于主鍵索引來(lái)說(shuō),主鍵一般都是不可被修改的。
- 非聚集索引
非聚集索引即索引結(jié)構(gòu)和數(shù)據(jù)分開(kāi)存放的索引。二級(jí)索引屬于非聚集索引。
非聚集索引的葉子節(jié)點(diǎn)并不一定存放數(shù)據(jù)的指針,因?yàn)槎?jí)索引的葉子節(jié)點(diǎn)就存放的是主鍵,根據(jù)主鍵再回表查數(shù)據(jù)。
非聚集索引的優(yōu)點(diǎn):
- 更新代價(jià)比聚集索引要小 。非聚集索引的更新代價(jià)就沒(méi)有聚集索引那么大了,非聚集索引的葉子節(jié)點(diǎn)是不存放數(shù)據(jù)的
非聚集索引的缺點(diǎn): - 同樣以來(lái)有序的數(shù)據(jù)
- 可能會(huì)二次查詢(回表):這應(yīng)該是非聚集索引最大的缺點(diǎn)了。 當(dāng)查到索引對(duì)應(yīng)的指針或主鍵后,可能還需要根據(jù)指針或主鍵再到數(shù)據(jù)文件或表中查詢。
這是mysql的文件截圖

聚集索引和非聚集索引:

因?yàn)槭菍?shí)戰(zhàn)面試,索引其他的問(wèn)題就不擴(kuò)展了
JVM內(nèi)存模型,垃圾清理算法
-
jdk1.8之前
image.png -
jdk1.8
image.png
堆
堆存放的是對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例以及數(shù)組都在這里分配內(nèi)存。
比如現(xiàn)在我們有個(gè)User類(lèi),
現(xiàn)在 User user = new User();
在user對(duì)象初始化的時(shí)候默認(rèn)code和name為null。(根據(jù)不同的數(shù)據(jù)類(lèi)型來(lái),比如int就默認(rèn)為0)
user.setName = "小明";
這里就把name從null重新賦值了小明。
從這里可以看出對(duì)象創(chuàng)建過(guò)程是 new對(duì)象->設(shè)默認(rèn)值->調(diào)用構(gòu)造方式設(shè)初始值

@Data
@Accessors(chain = true)
public class User {
private String code;
private String name;
}
方法區(qū)(元空間)
方法區(qū)屬于是 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)域的一塊邏輯區(qū)域,是各個(gè)線程共享的內(nèi)存區(qū)域。方法區(qū)存放類(lèi)信息、字段信息、方法信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存等數(shù)據(jù)。
棧 (本地方法棧,虛擬機(jī)棧,程序計(jì)數(shù)器)
垃圾回收算法
- 標(biāo)記-清除算法
該算法分為“標(biāo)記”和“清除”階段:首先標(biāo)記出所有不需要回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收掉所有沒(méi)有被標(biāo)記的對(duì)象。它是最基礎(chǔ)的收集算法,后續(xù)的算法都是對(duì)其不足進(jìn)行改進(jìn)得到。這種垃圾收集算法會(huì)帶來(lái)兩個(gè)明顯的問(wèn)題:
效率問(wèn)題
空間問(wèn)題(標(biāo)記清除后會(huì)產(chǎn)生大量不連續(xù)的碎片)
- 標(biāo)記-復(fù)制算法
為了解決效率問(wèn)題,“標(biāo)記-復(fù)制”收集算法出現(xiàn)了。它可以將內(nèi)存分為大小相同的兩塊,每次使用其中的一塊。當(dāng)這一塊的內(nèi)存使用完后,就將還存活的對(duì)象復(fù)制到另一塊去,然后再把使用的空間一次清理掉。這樣就使每次的內(nèi)存回收都是對(duì)內(nèi)存區(qū)間的一半進(jìn)行回收。 - 標(biāo)記-整理算法
根據(jù)老年代的特點(diǎn)提出的一種標(biāo)記算法,標(biāo)記過(guò)程仍然與“標(biāo)記-清除”算法一樣,但后續(xù)步驟不是直接對(duì)可回收對(duì)象回收,而是讓所有存活的對(duì)象向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。 - 分代收集算法
當(dāng)前虛擬機(jī)的垃圾收集都采用分代收集算法,這種算法沒(méi)有什么新的思想,只是根據(jù)對(duì)象存活周期的不同將內(nèi)存分為幾塊。一般將 java 堆分為新生代和老年代,這樣我們就可以根據(jù)各個(gè)年代的特點(diǎn)選擇合適的垃圾收集算法。
參考:

