1 hashCode
hashCode
的一般約定為:
- 同一個(gè)程序中多次調(diào)用返回相同的值肃弟。不會(huì)為
equals
方法比較對(duì)象提供信息碍现。 - 如果兩個(gè)對(duì)象
equals
結(jié)果為true
,那么hashCode
的結(jié)果也相等酝陈。 - 如果兩個(gè)對(duì)象
equals
結(jié)果為false
豺型,hashCode
結(jié)果可能相等也可能不相等。保證不相等對(duì)象的哈希值不同饼齿,有助于提高哈希表的性能饲漾。
2 equals
用于比較是否和傳入對(duì)象相等。
equals
的等價(jià)條件是:
- 自反性缕溉。任何非
null
引用x
有考传,x.equals(x)
返回true
。 - 對(duì)稱性证鸥。任何非
null
引用x
和y
有僚楞,x.equals(y)
返回ture
當(dāng)且僅當(dāng)y.equals(x)
也返回`true勤晚。 - 傳遞性。任何非
null
引用x
镜硕、y
和z
有运翼,如果x.equals(y)
且y.equals(z)
,那么x.equals(z)
兴枯。 - 一致性。任何非
null
引用x
矩欠、y
财剖,如果沒有修改對(duì)象,那么多次調(diào)用x.equals(y)
返回的結(jié)果是一致的癌淮。 - 任何非
null
引用躺坟。x.equals(null)
是false
。
Object
類對(duì)象比較特別乳蓄,x.equals(y)
為true
當(dāng)且僅當(dāng)x == y
為true
咪橙。
在重寫equals
方法時(shí),需要重寫hashCode
方法虚倒。為的是保證hashCode
的第1條特性能夠成立美侦。
3 clone
克隆結(jié)果的特性
-
x.clone != x
為true
。 -
x.clone.getClass() == x.getClass()
為true
魂奥,如果拷貝的過程中菠剩,調(diào)用了super.clone
(除Object
類之外)。 -
x.clone.equals(x)
為true
耻煤,如果重寫了equals
方法具壮。
克隆原理
通常,克隆對(duì)象應(yīng)該獨(dú)立于被克隆對(duì)象哈蝇。為了達(dá)到這樣的目的棺妓,可能需要在返回克隆對(duì)象前,修改克隆對(duì)象的字段炮赦,也就是說:
- 可變對(duì)象怜跑。需要將可變對(duì)象的引用替換為拷貝的引用。
- 不可變對(duì)象(初等類型或不可變引用)眼五∽彼遥克隆過程中就不需要修改
super.clone
的結(jié)果,一般來說虛擬機(jī)會(huì)創(chuàng)建新的對(duì)象看幼。如下代碼批旺,super.clone
返回的結(jié)構(gòu)已經(jīng)將a
和b
完成了。
public class Main implements Cloneable{
private int a;
private String b;
@Override
public Main clone() throws CloneNotSupportedException {
return (Main) super.clone();
}
}
Object
類的clone
方法
Object
類的clone
方法執(zhí)行的特定操作诵姜。
- 如果對(duì)象的類沒有實(shí)現(xiàn)接口
Cloneable
汽煮,那么會(huì)拋出CloneNotSupportedException
。 - 所有數(shù)組被認(rèn)為是默認(rèn)實(shí)現(xiàn)了接口
Cloneable
,數(shù)組類型T[]
的clone
方法的返回類型是T[]
暇赤,其中T
是任何引用或初等類型心例。否則,此方法將創(chuàng)建此對(duì)象類的新實(shí)例鞋囊,并使用此對(duì)象相應(yīng)字段的內(nèi)容初始化其所有字段止后;字段的內(nèi)容本身不會(huì)被克隆。由此可見溜腐,此方法執(zhí)行此對(duì)象的“淺拷貝”译株,而不是“深拷貝”操作。
Object
類沒有實(shí)現(xiàn)Cloneable
接口挺益,所以調(diào)用clone
方法會(huì)拋CloneNotSupportedException
歉糜。
4 notify
喚醒等待獲取對(duì)象監(jiān)控器(monitor)的一個(gè)線程。如果有多個(gè)線程在等待望众,則被喚醒線程是不確定的匪补。
被喚醒線程不能立即執(zhí)行,而是等到當(dāng)前線程釋放對(duì)象鎖才可以執(zhí)行烂翰。被喚醒的線程需要與任何其他線程競爭夯缺,這其中不乏主動(dòng)基于此對(duì)象同步的線程。
該方法只能由對(duì)象monitor擁有者線程來調(diào)用刽酱。線程成為monitor擁有者方式有:
-
synchronized
實(shí)例方法喳逛。 -
synchronized
語句塊。 -
synchronized
靜態(tài)方法棵里。即Class
實(shí)例的方法润文。
Java對(duì)象的實(shí)現(xiàn)由Monitor Object、Monitor Lock和Monitor Condition三部分組成殿怜。[2]
5 wait
使當(dāng)前線程等待典蝌,直到另一個(gè)線程調(diào)用notify
方法或notifyAll
方法、或者超時(shí)头谜。
當(dāng)前線程必須用于對(duì)象monitor骏掀。
此方法使當(dāng)前線程被放入這個(gè)對(duì)象的等待集中,然后釋放所有這個(gè)對(duì)象上的同步聲明柱告。線程
進(jìn)入休眠狀態(tài)截驮,直到:
- 其他線程調(diào)用對(duì)象的
notify
,線程恰好被選中际度。
- 其他線程調(diào)用對(duì)象的
notifyAll
葵袭。 - 其他線程調(diào)用
的
interrupt
方法。 - 用盡超時(shí)時(shí)間乖菱。
線程喚醒后坡锡,會(huì)先從等待集合中移除蓬网,并重新進(jìn)入調(diào)度行列。被喚醒線程與其他線程同步以常規(guī)方式競爭對(duì)象同步的權(quán)限鹉勒。一旦獲取了對(duì)象所有權(quán)帆锋,所有的對(duì)象同步聲明將恢復(fù)為原狀(quo ante),即調(diào)用wait
時(shí)的狀態(tài)禽额。
線程也可以在不被通知锯厢、中斷或超時(shí)的情況下被喚醒,即所謂的“虛假喚醒”绵疲。雖然哲鸳,這種情況在實(shí)踐中很少發(fā)生,但應(yīng)用程序必須通過測試本應(yīng)導(dǎo)致線程被喚醒的條件盔憨,并在條件不滿足時(shí)繼續(xù)等待來防范這種情況。換句話說讯沈,等待應(yīng)該總是以循環(huán)的形式出現(xiàn)郁岩,就像這樣:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
// Perform action appropriate to condition
}
如果當(dāng)前線程在等待之前或等待期間被任何線程中斷,則拋出InterruptedException
缺狠。只是在對(duì)象的鎖狀態(tài)恢復(fù)之前问慎,不會(huì)拋出。也就是說挤茄,如果當(dāng)前線程被中斷時(shí)如叼,對(duì)象monitor被其他線程擁有,當(dāng)前線程只有獲得對(duì)象monitor才能夠拋出異常穷劈。
注意笼恰,wait
方法在將當(dāng)前線程放入此對(duì)象的等待集中時(shí),只解鎖此對(duì)象歇终;在線程等待期間社证,當(dāng)前線程可能同步的任何其他對(duì)象都將保持鎖定狀態(tài)。
6 finalize
當(dāng)垃圾回收器確定對(duì)象不再被引用時(shí)评凝,垃圾回收器調(diào)用對(duì)象的這個(gè)方法追葡。子類重寫finalize
方法,用于釋放系統(tǒng)資源或執(zhí)行其他清理工作奕短。
關(guān)于finalize
一般約定:
- 當(dāng)不再有任何存活線程以任何方式訪問該對(duì)象時(shí)宜肉,則調(diào)用finalize,除非已經(jīng)被某個(gè)對(duì)象或類執(zhí)行
finalize
時(shí)調(diào)用過翎碑。
finalize
方法的用途:
- 使此對(duì)象對(duì)其他線程再次可用谬返。
- 在對(duì)象被回收之前執(zhí)行清理操作。例如杈女,I/O連接對(duì)象的finalize方法可能會(huì)執(zhí)行顯式I/O事務(wù)朱浴,以便在對(duì)象被回收之前斷開連接吊圾。
Java并不保證哪個(gè)線程將調(diào)用對(duì)象的finalize
方法,但是翰蠢,可以保證的是調(diào)用finalize
的線程在調(diào)用finalize時(shí)不會(huì)持有任何用戶可見的同步鎖项乒。如果finalize
方法執(zhí)行時(shí)拋出未捕獲的異常,則將忽略該異常梁沧,并終止執(zhí)行該對(duì)象的finalization檀何。
調(diào)用對(duì)象finalize
方法之后,虛擬機(jī)不會(huì)做任何動(dòng)作廷支,直到它再次確定不再有任何活躍線程以任何方法引用該對(duì)象频鉴,包括其他即將終止的對(duì)象或類可能執(zhí)行的操作,這時(shí)恋拍,對(duì)象可能會(huì)被丟棄垛孔。
對(duì)于一個(gè)對(duì)象,finalize
方法不會(huì)被虛擬機(jī)調(diào)用多次施敢,也就是說最多一次周荐。
代碼實(shí)例:
static class Test {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("Finalized!!!");
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Test test = new Test();
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + " finished");
});
thread.start();
thread.join(); // 如果注釋掉,則不會(huì)執(zhí)行finalize
System.gc();
TimeUnit.SECONDS.sleep(10);
}