所有的java對(duì)象都隱式繼承了Object類對(duì)象。所有的java對(duì)象都擁有Object默認(rèn)的方法。
public final native Class<?>getClass();//返回字節(jié)碼文件對(duì)象 java反射實(shí)現(xiàn)方式之一
public native int hashCode();
public boolean equals(Object obj)
protected Object clone();
public String toString();
public final void notify();
public final void notifyAll();
public final void wait(long timeout);
protected void finalized();
1.equals和hashCode
查看完文檔以后我們查看源碼,發(fā)現(xiàn)hashCode是由native關(guān)鍵字修飾,equals方法則是直接使用==比較了內(nèi)存地址。
public boolean equals(Object obj) {
return (this == obj);
}
equals和hashCode用來(lái)標(biāo)識(shí)對(duì)象,可以在非排序的情況下比較兩個(gè)對(duì)象是否相等(對(duì)象數(shù)組中可以使用比較器)。
那么我們仔細(xì)關(guān)注一下hashCode源碼所給出的注釋
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link java.lang.Object#equals(java.lang.Object)}
* method, then calling the {@code hashCode} method on each of the
* two objects must produce distinct integer results. However, the
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables.
* </ul>
* <p>
* As much as is reasonably practical, the hashCode method defined by
* class {@code Object} does return distinct integers for distinct
* objects. (This is typically implemented by converting the internal
* address of the object into an integer, but this implementation
* technique is not required by the
* Java™ programming language.)
- 返回一個(gè)哈希值給對(duì)象,這個(gè)方法有益于底層結(jié)構(gòu)是哈希表的結(jié)構(gòu)對(duì)象,例如HashMap
- 如果兩個(gè)對(duì)象的equals的結(jié)果是相等的,則調(diào)用hashCode返回的int也必須是相同的
- 如果兩個(gè)對(duì)象的equals不相等,hashCode可以不相等,但是如果equasl不相等,hashCode也不相等的話,有利于提高散列性能。(Map集合和Set集合底層判斷重復(fù)的時(shí)候,先判斷hashCode是否相等,如相等,再判斷key的equals是否相等,一旦短路與&&生效,會(huì)大大提高程序執(zhí)行效率。)
- hashCode默認(rèn)是由對(duì)象的地址轉(zhuǎn)換而來(lái),同時(shí)根據(jù)不同的對(duì)象轉(zhuǎn)成不同的hash值(但這種實(shí)現(xiàn)不是java語(yǔ)言要求的 所以我們常常重寫(xiě)它)
適用場(chǎng)景:我們?cè)谶m用自定義對(duì)象作為Map/Set鍵時(shí),為了區(qū)分不同對(duì)象,必須重寫(xiě)hashCode和equals。
延申:equals和==的區(qū)別:
對(duì)于基本類型而言,==比較的是內(nèi)容。
對(duì)于引用數(shù)據(jù)類型而言,==比較的是地址。
對(duì)于引用數(shù)據(jù)類型(String,Integer,date等),重寫(xiě)了equals和hashCode的,比較的就是內(nèi)容。
對(duì)于引用數(shù)據(jù)類型,沒(méi)有重寫(xiě)equals和hashCode的,適用的還是Object的equals方法,比較的是地址。
再延申:那我們就去看一看String重寫(xiě)的equals源碼吧:
public boolean equals(Object anObject) {
if (this == anObject) {//先判斷地址是否相等,地址相等直接返回
return true;
}
if (anObject instanceof String) {//判斷是否是String類,為了向下轉(zhuǎn)型的安全
String anotherString = (String)anObject;
int n = value.length;//value就是本String轉(zhuǎn)化成的字符數(shù)組
if (n == anotherString.value.length) {//比較兩者的字符數(shù)組是否相等
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {//從前往后一個(gè)字符一個(gè)字符比較
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
OK,那么我們知道了,String先是判斷兩個(gè)對(duì)象的地址是否相等,然后向下轉(zhuǎn)型,再轉(zhuǎn)成字符數(shù)組,從后向前遍歷比較。
2.toString
/**
* Returns a string representation of the object. In general, the
* {@code toString} method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
* <p>
* The {@code toString} method for class {@code Object}
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `{@code @}', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
* <blockquote>
* <pre>
* getClass().getName() + '@' + Integer.toHexString(hashCode())
* </pre></blockquote>
*
* @return a string representation of the object.
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- 用文本方式標(biāo)識(shí)一個(gè)對(duì)象
- Object默認(rèn)返回的是 字節(jié)碼文件的名稱+@+一個(gè)內(nèi)存地址的int映射
clone()方法
一般java的賦值是復(fù)制對(duì)象的引用(=),(類初始化狀態(tài)不一)淺拷貝。要實(shí)現(xiàn)深拷貝,(連成員變量初始化狀態(tài)都一樣)成員變量都拷貝出去一份(如果是可變的引用),因而"="是屬于淺拷貝。
所以深拷貝是成員變量(如果是可變的引用)都復(fù)制一份,淺拷貝則是不復(fù)制成員變量。兩者初始化程度不一。
clone用法:
- 克隆的對(duì)象要實(shí)現(xiàn)Cloneable接口
- 重寫(xiě)clone方法,最好修飾成public
范例:淺拷貝Time
public class Time implements Cloneable{
//可變成員變量
private Date date;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
范例:深拷貝Time
public class Time implements Cloneable{
//可變成員變量
private Date date;
@Override
protected Object clone() throws CloneNotSupportedException {
//向下轉(zhuǎn)型 拷貝Time對(duì)象
Time time=(Time)super.clone();
//拷貝可變的成員變量
time.date=(Date)date.clone();
//返回拷貝的對(duì)象
return time;
}
}
wait和notify方法
這是線程間通信的API
- 無(wú)論是wait、notify還是notifyAll()都需要由監(jiān)聽(tīng)器對(duì)象(鎖對(duì)象)來(lái)進(jìn)行調(diào)用,他們都是在同步代碼塊中調(diào)用的,否則會(huì)拋出異常!
- notify()喚醒的是在等待隊(duì)列的某個(gè)線程(不確定會(huì)喚醒哪個(gè)),notifyAll()喚醒的是等待隊(duì)列所有線程
- 導(dǎo)致wait()的線程被喚醒可以有4種情況
- 該線程被中斷
- wait()時(shí)間到了
- 被notify()喚醒
- 被notifyAll()喚醒
- 調(diào)用wait()的線程會(huì)釋放掉鎖
一些面試題:
為什么wait和notify在Object方法上?
因?yàn)殒i是對(duì)象鎖,讓線程等待某個(gè)對(duì)象的鎖,應(yīng)該由對(duì)象來(lái)操作
notify方法調(diào)用后,會(huì)發(fā)生什么?
會(huì)喚醒等待隊(duì)列的某個(gè)線程
注:并不會(huì)立刻喚醒,會(huì)等notify的synchronized代碼塊執(zhí)行完之后才會(huì)獲得鎖對(duì)象
Thread.sleep和Object.wait區(qū)別?
sleep不會(huì)釋放對(duì)象鎖的控制,而wait會(huì)。
finalize方法
這是在GC前會(huì)被JVM調(diào)用的方法,用來(lái)對(duì)一些特定的內(nèi)存進(jìn)行GC,一般不重寫(xiě),對(duì)一些JNI操作的gc會(huì)使用。
因而hashCode和equals用于對(duì)象比較,clone用于對(duì)象克隆,toString用于對(duì)象標(biāo)識(shí),notify與wait是對(duì)象鎖相關(guān)。