最近通過某大佬的建議準備閱讀一下JDK的源碼來提高一下本身
因此開始寫JDK源碼分析的文章
java
閱讀JDK版本爲1.8面試
類構造器是建立Java對象的方法之一。通常咱們都使用new關鍵字來進行實例,還能夠在構造器中進行相應的初始化操做。
在一個Java類中必須存在一個構造器,若是沒有添加系統在編譯時會默認建立一個無參構造。算法
/*實例一個Object對象*/
Object obj = new Object()
複製代碼
在面試中面試官常常會問 equals() 方法和 == 運算符的區別,== 運算符用於比較基本類型的值是否相同而 equals 用於比較兩個對象是否相等,那麼有個問題來了,兩個對象怎麼纔算是相等的呢。 看object中的equals實現bash
public boolean equals(Object obj) {
return (this == obj);
}
複製代碼
在Object中equals和==是等價的。因此在Object中兩個對象的引用相同,那麼必定就是相同的。在咱們自定義對象的時候必定要重寫equals方法。我參考瞭如下網上的資料來分析一下String中重寫的 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;
}
複製代碼
String 是引用類型,比較時不能比較引用是否相等,重點是字符串的內容是否相等。因此 String 類定義兩個對象相等的標準是字符串內容都相同。
ide
在Java規範中,對 equals 方法的使用必須遵循如下幾個原則:
源碼分析
public class Student {
private String name;
/**
* 無參構造方法
*/
public Student() {
}
/**
* 無參構造方法
*/
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
//引用相同 兩個對象確定是相同的
if(this==obj){
return true;
}
//對象等於空 或者不是Student 是不想等的
if(obj==null || !(obj instanceof Student)){
return false;
}
//轉爲Student對象
Student student = (Student)obj;
//屬性相同 返回true
return this.getName()==student.getName();
}
}
複製代碼
而後建立一個測試類來進行測試:測試
Student t1 = new Student("yes");
Student t2 = new Student("slm");
System.out.println("對象不一樣 屬性不一樣 == "+(t1==t2));
System.out.println("對象不一樣 屬性不一樣 equals "+(t1.equals(t2)));
Student t3 = new Student("slm");
System.out.println("對象不一樣 屬性相同"+(t2.equals(t3)));
複製代碼
輸出結果:
ui
對象不一樣 屬性不一樣 == false
對象不一樣 屬性不一樣 equals false
對象不一樣 屬性相同truethis
如今能夠看出 若是在這裏不重寫equals方法的話永遠只會執行Object的equals也就是經過==對比對象引用地址是否相同。
下面再看一個例子,這個時候若是出現一個Student的子類咱們在對比一下
/**
* @Author: sunluomeng
* @CreateTime: 2019-06-06 23:35
* @Description:
*/
public class Language extends Student{
private String name;
/**
* 無參構造
*/
public Language(){
}
/**
* 有參構造
* @param name
*/
public Language(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
//引用相同 兩個對象確定是相同的
if(this==obj){
return true;
}
//對象等於空 或者不是Student 是不想等的
if(obj==null || !(obj instanceof Language)){
return false;
}
//轉爲Student對象
Language language = (Language)obj;
//屬性相同 返回true
return this.getName()==language.getName();
}
}
複製代碼
這個時候咱們的新建立的Language類繼承Student而後建立兩個對象去作比較
父類對比子類 屬性相同---true
子類對比父類 屬性相同---false
能夠看出父類去對比子類既 student.equals(language) 結果爲true 而子類去對比父類 既 language.equals(student) 返回false
這樣的話就違反了問哦們上面說到的對稱性
對於任何非空引用值 x 和 y,當且僅當 y.equals(x) 返回 true 時,x.equals(y) 才應返回 true
若是y是Student x 是Language
那麼如今就是 y.equals(x) 等於true 反過來x.equals(y)也應該返回true,可是如今爲何會返回false呢?
先來看一下代碼
java 中的instanceof 運算符是用來在運行時指出對象是不是特定類的一個實例。instanceof經過返回一個布爾值來指出,這個對象是不是這個特定類或者是它的子類的一個實例。
這樣的話也就是說 Language是Student的子類 在用instanceof判斷的時候是返回true,而Language雖然是繼承Student 可是使用instanceof判斷的時候會發現 Language和Student的類型不一樣 而後Student也不是Language的子類因此會返回false。
而解決的辦法就是
而後咱們在運行一下剛剛的代碼
輸出結果:
父類對比子類 屬性相同---false
子類對比父類 屬性相同---false
完美解決,知足對稱性
注意:使用getClass是要根據狀況而定,使用getClass 不符合多態的定義
那何時使用instanceof,何時使用getClass呢?
還有就是必定要注意不管什麼時候重寫此方法,一般都必須重寫hashCode方法,以維護hashCode方法的通常約定,該方法聲明相等對象必須具備相同的哈希代碼。
咱們首先看一下getClass在Object中的實現。
能夠看出getClass是返回一個運行時的對象。class是返回編譯的類對象
能夠看到getClass方法被final修飾,說明此方法不能被重寫。
先看一下hashCode在Object中的實現:
hashCode也是一個被native修飾的本地方法
註釋說明的是返回該對象的哈希值。那麼它有什麼做用呢?
主要是保證基於散列的集合,如HashSet、HashMap以及HashTable等,在插入元素時保證元素不可重複,同時爲了提升元素的插入刪除便利效率而設計;主要是爲了查找的便捷性而存在。
就好比使用Set進行舉例子。
Set集合是不可重複的,若是每次添加數據都使用equals去作對比的話,插入十萬條數據就要對比十萬次效率是很是慢的。
因此在添加數據的時候使用了哈希表,哈希算法也稱之爲散列算法,當添加一個值的時候先算出它的哈希值根據算出的哈希值將數據插入指定位置。這樣的話就避免了一直調用equals形成的效率隱患。同時有如下條件:
還有一種狀況是兩個元素不相同,可是hashCode相同,這就是哈希碰撞。
若是發生了hash key相同的狀況就在相同的元素建立一個鏈表。把全部相同的元素存放在鏈表中。
先看toString的實現
源碼中實現方法:
源碼實現:
還有notify()/notifyAll()/wait()等寫到多線程的時候在作分析
小弟不才,若有錯誤請指出。喜歡請關注,慢慢更新JDK源碼閱讀筆記
** 小弟公衆號,亂敲代碼。歡迎點贊,關注**![]()