自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java 基礎(chǔ) | Object 源碼解析

開(kāi)發(fā) 后端
Java 是一門面向?qū)ο蟮恼Z(yǔ)言,在 Java 里面一切都可以看作是一個(gè)對(duì)象,而 Java 里面所有的對(duì)象都默認(rèn)繼承于 Object 類。

[[355023]]

 前言

Java 是一門面向?qū)ο蟮恼Z(yǔ)言,在 Java 里面一切都可以看作是一個(gè)對(duì)象,而 Java 里面所有的對(duì)象都默認(rèn)繼承于 Object 類。

本文基于JDK1.8


可以看到一共12個(gè)方法,其中 registerNatives() 是 native 修飾的,一個(gè)本地方法,具體是用C(C++)在DLL中實(shí)現(xiàn)的,然后通過(guò)JNI調(diào)用。

getClass

  1. public final native Class getClass(); 

getClass 也是個(gè) native 方法,這個(gè)方法的作用就是返回某個(gè)對(duì)象的運(yùn)行時(shí)類,它的返回值是 Class 類型,Class c = obj.getClass();通過(guò)對(duì)象 c ,我們可以獲取該對(duì)象的所有成員方法,每個(gè)成員方法都是一個(gè) Method 對(duì)象;我們也可以獲取該對(duì)象的所有成員變量,每個(gè)成員變量都是一個(gè) Field 對(duì)象;同樣的,我們也可以獲取該對(duì)象的構(gòu)造函數(shù),構(gòu)造函數(shù)則是一個(gè) Constructor 對(duì)象。這個(gè)方法在反射時(shí)會(huì)常用到。

hashCode

  1. public native int hashCode(); 
  • hashCode 方法返回散列值。
  • 返回值默認(rèn)是由對(duì)象的地址轉(zhuǎn)換而來(lái)的。
  • 同一個(gè)對(duì)象調(diào)用 hashCode 的返回值是相等的。
  • 兩個(gè)對(duì)象的 equals 相等,那 hashCode 一定相等。
  • 兩個(gè)對(duì)象的 equals 不相等,那 hashCode 也不一定相等。

equals

  1. public boolean equals(Object obj) { 
  2.     return (this == obj); 

 equals 的實(shí)現(xiàn)非常簡(jiǎn)單,它的作用就是比較兩個(gè)對(duì)象是否相等,而比較的依據(jù)就是二者的內(nèi)存地址。除此之外,equals 還遵循以下幾個(gè)原則:

  1. 1、自反性:x.equals(x);  // true 
  2. 2、對(duì)稱性:x.equals(y) == y.equals(x);  // true 
  3. 3、傳遞性:if (x.equals(y) && y.equals(z)) 
  4.             x.equals(z); // true
  5. 4、一致性,只要對(duì)象沒(méi)有被修改,多次調(diào)用 equals() 方法結(jié)果不變: 
  6. x.equals(y) == x.equals(y); // true  
  7. 5、非空性,對(duì)任何不是 null 的對(duì)象 x 調(diào)用 x.equals(null) 結(jié)果都為 false : 
  8. x.equals(null); // false

 為什么要重寫(xiě) hashcode 和 equals ?

因?yàn)檫@兩個(gè)方法都跟對(duì)象的比較有關(guān),所以如果在程序中要做對(duì)象比較,那大概率要重寫(xiě)這兩個(gè)方法了。因?yàn)閑quals默認(rèn)的比較邏輯就是對(duì)象的地址進(jìn)行比較,兩個(gè)對(duì)象內(nèi)存地址肯定不同,所以無(wú)論如何兩個(gè)對(duì)象通過(guò)eqals比較肯定返回false。

但在實(shí)際編程中,我們經(jīng)常會(huì)遇到去重,或者將對(duì)象放到有序集合中,或者將對(duì)象存入無(wú)重復(fù)的集合中,這時(shí)如果沒(méi)有重寫(xiě)equals和hashCode,則無(wú)法達(dá)到需求。

舉個(gè)例子,系統(tǒng)中同時(shí)存在兩個(gè)對(duì)象,對(duì)象A和對(duì)象B,其姓名和身份證號(hào)一模一樣。此時(shí),在系統(tǒng)內(nèi)存中是兩個(gè)對(duì)象,但其內(nèi)容一致分明是一個(gè)人同時(shí)產(chǎn)生了兩條重復(fù)信息。如果使用默認(rèn)的equals方法比較,則這兩個(gè)對(duì)象永遠(yuǎn)不相等,永遠(yuǎn)不能比出來(lái)是一條相同的重復(fù)信息。所以,要重寫(xiě)equals和hashCode方法來(lái)達(dá)到以上需求效果。

clone 

  1. protected native Object clone() throws CloneNotSupportedException; 

clone() 是 Object 的 protected 方法,它不是 public,一個(gè)類不顯式去重寫(xiě) clone(),其它類就不能直接去調(diào)用該類實(shí)例的 clone() 方法。此外,Clone 的注釋中還提到比較重要的幾點(diǎn):

  • 克隆的對(duì)象必須要實(shí)現(xiàn) Cloneable 接口并重寫(xiě) clone 方法,否則會(huì)報(bào) CloneNotSupportedException 異常
  • clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一個(gè) protected 方法。Cloneable 接口只是規(guī)定,如果一個(gè)類沒(méi)有實(shí)現(xiàn) Cloneable 接口又調(diào)用了 clone() 方法,就會(huì)拋出 CloneNotSupportedException。
  • 淺拷貝:拷貝對(duì)象和原始對(duì)象的引用類型引用同一個(gè)對(duì)象。
  • 深拷貝:拷貝對(duì)象和原始對(duì)象的引用類型引用不同對(duì)象。

關(guān)于淺拷貝與深拷貝我們后面再討論。

toString

  1. public String toString() { 
  2.  return getClass().getName() + "@" + Integer.toHexString(hashCode()); 

 返回該對(duì)象的字符串表示,非常重要的方法

  • getClass().getName(); 獲取字節(jié)碼文件的對(duì)應(yīng)全路徑名例如java.lang.Object;
  • Integer.toHexString(hashCode()); 將哈希值轉(zhuǎn)成16進(jìn)制數(shù)格式的字符串。

wait 和 notify

  1. public final void wait() throws InterruptedException { 
  2.      wait(0); 
  3.  
  4. public final native void wait(long timeout) throws InterruptedException; 
  5.  
  6. public final void wait(long timeout, int nanos) throws InterruptedException { 
  7.         if (timeout < 0) { 
  8.             throw new IllegalArgumentException("timeout value is negative"); 
  9.         } 
  10.  
  11.         if (nanos < 0 || nanos > 999999) { 
  12.             throw new IllegalArgumentException( 
  13.                                 "nanosecond timeout value out of range"); 
  14.         } 
  15.  
  16.         if (nanos > 0) { 
  17.             timeout++; 
  18.         } 
  19.  
  20.         wait(timeout); 

 wait 的作用是讓當(dāng)前線程進(jìn)入等待狀態(tài),同時(shí),wait() 也會(huì)讓當(dāng)前線程釋放它所持有的鎖。直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,當(dāng)前線程被喚醒進(jìn)入就緒狀態(tài)。

wait(long timeout) (以毫秒為單位)讓當(dāng)前線程處于等待(阻塞)狀態(tài),直到其他線程調(diào)用此對(duì)象的notify() 方法或 notifyAll() 方法,或者超過(guò)指定的時(shí)間量,當(dāng)前線程被喚醒進(jìn)入就緒狀態(tài)。

wait(long timeout, int nanos) 和 wait(long timeout) 功能一樣,唯一的區(qū)別是這個(gè)可以提供更高的精度??偝瑫r(shí)時(shí)間(以納秒為單位)計(jì)算為 1000000 *timeout+ nanos。By the way ,wait(0,0) 和 wait(0) 效果一樣。

  1. ublic final native void notify(); 
  2. public final native void notifyAll(); 

 首先是 notify ,notify 的作用就是隨機(jī)喚醒在等待隊(duì)列的某個(gè)線程,而 notifyAll 就是喚醒在等待隊(duì)列的所有線程。

注意:notify 和 wait 方法的使用規(guī)范。意思就是這二者必須在 synchronized 修飾的同步方法或同步代碼中使用。

Thread.sleep() 和 Object.wait() 有什么區(qū)別?

首先,二者都可以暫停當(dāng)前線程,釋放 CPU 控制權(quán)。主要的區(qū)別在于 Object.wait()在釋放 CPU 同時(shí),釋放了對(duì)象鎖的控制。而 Thread.sleep() 沒(méi)有對(duì)鎖釋放。換句話說(shuō) sleep 就是耍流氓,占著茅坑不拉屎。

完整代碼

  1. package java.lang; 
  2.  
  3.  
  4. public class Object { 
  5.  
  6.     /** 
  7.      * 一個(gè)本地方法,具體是用C(C++)在DLL中實(shí)現(xiàn)的,然后通過(guò)JNI調(diào)用 
  8.      */ 
  9.     private static native void registerNatives(); 
  10.  
  11.     /** 
  12.      * 對(duì)象初始化時(shí)自動(dòng)調(diào)用此方法 
  13.      */ 
  14.     static { 
  15.         registerNatives(); 
  16.     } 
  17.  
  18.     /** 
  19.      * 返回此Object的運(yùn)行時(shí)類 
  20.      */ 
  21.     public final native Class<?> getClass(); 
  22.  
  23.     /** 
  24.      * hashCode的常規(guī)協(xié)定是: 
  25.      * 1.在java應(yīng)用程序執(zhí)行期間,在對(duì)同一對(duì)象多次調(diào)用hashCode()方法時(shí),必須一致地返回相同的整數(shù),前提是將對(duì)象進(jìn)行equals比較時(shí)所用的信息沒(méi)有被修改。 
  26.      * 從某一應(yīng)用程序的一次執(zhí)行到同一應(yīng)用程序的另一次執(zhí)行,該整數(shù)無(wú)需保持一致。 
  27.      * 2.如果根據(jù)equals(object)方法,兩個(gè)對(duì)象是相等的,那么對(duì)這兩個(gè)對(duì)象中的每個(gè)對(duì)象調(diào)用hashCode方法都必須生成相同的整數(shù)結(jié)果。 
  28.      * 3.如果根據(jù)equals(java.lang.Object)方法,兩個(gè)對(duì)象不相等,那么對(duì)這兩個(gè)對(duì)象中的任一對(duì)象上調(diào)用hashCode()方法不要求一定生成不同的整數(shù)結(jié)果。 
  29.      * 但是,程序員應(yīng)該意識(shí)到,為不相等的對(duì)象生成不同整數(shù)結(jié)果可以提高哈希表的性能。 
  30.      */ 
  31.     public native int hashCode(); 
  32.  
  33.     /** 
  34.      * 這里比較的是對(duì)象的內(nèi)存地址 
  35.      */ 
  36.     public boolean equals(Object obj) { 
  37.         return (this == obj); 
  38.     } 
  39.  
  40.     /** 
  41.      * 本地clone方法,用于對(duì)象的復(fù)制 
  42.      */ 
  43.     protected native Object clone() throws CloneNotSupportedException; 
  44.  
  45.     /** 
  46.      * 返回該對(duì)象的字符串表示,非常重要的方法 
  47.      * getClass().getName();獲取字節(jié)碼文件的對(duì)應(yīng)全路徑名例如java.lang.Object 
  48.      * Integer.toHexString(hashCode());將哈希值轉(zhuǎn)成16進(jìn)制數(shù)格式的字符串。 
  49.      */ 
  50.     public String toString() { 
  51.         return getClass().getName() + "@" + Integer.toHexString(hashCode()); 
  52.     } 
  53.  
  54.     /** 
  55.      * 不能被重寫(xiě),用于喚醒一個(gè)在因等待該對(duì)象(調(diào)用了wait方法)被處于等待狀態(tài)(waiting 或 time_wait)的線程,該方法只能同步方法或同步塊中調(diào)用 
  56.      */ 
  57.     public final native void notify(); 
  58.  
  59.     /** 
  60.      * 不能被重寫(xiě),用于喚醒所有在因等待該對(duì)象(調(diào)用wait方法)被處于等待狀態(tài)(waiting或time_waiting)的線程,該方法只能同步方法或同步塊中調(diào)用 
  61.      */ 
  62.     public final native void notifyAll(); 
  63.  
  64.     /** 
  65.      * 不能被重寫(xiě),用于在線程調(diào)用中,導(dǎo)致當(dāng)前線程進(jìn)入等待狀態(tài)(time_waiting),timeout單位為毫秒,該方法只能同步方法或同步塊中調(diào)用,超過(guò)設(shè)置時(shí)間后線程重新進(jìn)入可運(yùn)行狀態(tài) 
  66.      */ 
  67.     public final native void wait(long timeout) throws InterruptedException; 
  68.  
  69.  
  70.     public final void wait(long timeout, int nanos) throws InterruptedException { 
  71.         if (timeout < 0) { 
  72.             throw new IllegalArgumentException("timeout value is negative"); 
  73.         } 
  74.  
  75.         if (nanos < 0 || nanos > 999999) { 
  76.             throw new IllegalArgumentException( 
  77.                     "nanosecond timeout value out of range"); 
  78.         } 
  79.  
  80.         if (nanos > 0) { 
  81.             timeout++; 
  82.         } 
  83.  
  84.         wait(timeout); 
  85.     } 
  86.  
  87.     /** 
  88.      * 在其他線程調(diào)用此對(duì)象的notify()方法或notifyAll()方法前,導(dǎo)致當(dāng)前線程等待。換句話說(shuō),此方法的行為就好像它僅執(zhí)行wait(0)調(diào)用一樣。 
  89.      * 當(dāng)前線程必須擁有此對(duì)象監(jiān)視器。 
  90.      * 該線程發(fā)布對(duì)此監(jiān)視器的所有權(quán)并等待,直到其他線程通過(guò)調(diào)用notify方法或notifyAll方法通知在此對(duì)象的監(jiān)視器上等待的線程醒來(lái), 
  91.      * 然后該線程將等到重新獲得對(duì)監(jiān)視器的所有權(quán)后才能繼續(xù)執(zhí)行。 
  92.      */ 
  93.     public final void wait() throws InterruptedException { 
  94.         wait(0); 
  95.     } 
  96.  
  97.     /** 
  98.      * 這個(gè)方法用于當(dāng)對(duì)象被回收時(shí)調(diào)用,這個(gè)由JVM支持,Object的finalize方法默認(rèn)是什么都沒(méi)有做,如果子類需要在對(duì)象被回收時(shí)執(zhí)行一些邏輯處理,則可以重寫(xiě)finalize方法。 
  99.      */ 
  100.     protected void finalize() throws Throwable { 
  101.     } 

 PS:這里有一個(gè)技術(shù)交流群(扣扣群:1158819530),方便大家一起交流,持續(xù)學(xué)習(xí),共同進(jìn)步,有需要的可以加一下。

 

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2021-03-24 07:16:57

RocketMQ源碼解析Topic

2015-09-16 09:10:27

Java源碼解析

2021-02-08 08:45:18

Java內(nèi)部類Object類

2021-07-03 08:51:30

源碼Netty選擇器

2015-09-11 09:17:55

JavaJava HashMa

2020-10-20 10:17:20

Java泛型Type

2022-05-20 10:32:49

事件循環(huán)器事件隊(duì)列鴻蒙

2017-04-05 20:00:32

ChromeObjectJS代碼

2009-11-02 14:55:52

VB.NET Obje

2010-10-29 09:34:16

2013-06-08 10:11:31

Java線程池架構(gòu)

2015-10-10 09:39:42

Java線程池源碼解析

2021-02-20 06:09:46

libtask協(xié)程鎖機(jī)制

2012-11-06 11:07:59

jQueryJSjQuery框架

2021-07-09 06:48:30

注冊(cè)源碼解析

2024-11-18 16:15:00

2024-01-18 08:31:22

go實(shí)現(xiàn)gorm框架

2020-01-12 19:10:30

Java程序員數(shù)據(jù)

2021-05-26 11:30:24

Java線程池代碼

2010-06-13 15:28:56

UML基礎(chǔ)與應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)