欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

深入淺析Java中的Object類

今天就跟大家聊聊有關深入淺析Java中的Object類,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

創(chuàng)新互聯(lián)公司是專業(yè)的五指山網(wǎng)站建設公司,五指山接單;提供成都做網(wǎng)站、成都網(wǎng)站設計,網(wǎng)頁設計,網(wǎng)站設計,建網(wǎng)站,PHP網(wǎng)站建設等專業(yè)做網(wǎng)站服務;采用PHP框架,可快速的進行五指山網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

Java作為一個龐大的知識體系,涉及到的知識點繁多,本文將從Java中最基本的類java.lang.Object開始談起。

Object類是Java中其他所有類的祖先類,沒有Object類Java面向?qū)ο鬅o從談起。作為其他所有類的基類,Object具有哪些屬性和行為,是Java語言設計背后的思維體現(xiàn)。

Object類位于java.lang包中,java.lang包包含著Java最基礎和核心的類,在編譯時會自動導入。Object類沒有定義屬性,一共有13個方法,具體的類定義結(jié)構(gòu)如下圖:

深入淺析Java中的Object類

1.類構(gòu)造器public Object();

大部分情況下,Java中通過形如 new A(args..)形式創(chuàng)建一個屬于該類型的對象。其中A即是類名,A(args..)即此類定義中相對應的構(gòu)造函數(shù)。通過此種形式創(chuàng)建的對象都是通過類中的構(gòu)造函數(shù)完成。為體現(xiàn)此特性,Java中規(guī)定:在類定義過程中,對于未定義構(gòu)造函數(shù)的類,默認會有一個無參數(shù)的構(gòu)造函數(shù),作為所有類的基類,Object類自然要反映出此特性,在源碼中,未給出Object類構(gòu)造函數(shù)定義,但實際上,此構(gòu)造函數(shù)是存在的。

當然,并不是所有的類都是通過此種方式去構(gòu)建,也自然的,并不是所有的類構(gòu)造函數(shù)都是public。

2.private static native void registerNatives();

registerNatives函數(shù)前面有native關鍵字修飾,Java中,用native關鍵字修飾的函數(shù)表明該方法的實現(xiàn)并不是在Java中去完成,而是由C/C++去完成,并被編譯成了.dll,由Java去調(diào)用。方法的具體實現(xiàn)體在dll文件中,對于不同平臺,其具體實現(xiàn)應該有所不同。用native修飾,即表示操作系統(tǒng),需要提供此方法,Java本身需要使用。具體到registerNatives()方法本身,其主要作用是將C/C++中的方法映射到Java中的native方法,實現(xiàn)方法命名的解耦。
既然如此,可能有人會問,registerNatives()修飾符為private,且并沒有執(zhí)行,作用何以達到?其實,在Java源碼中,此方法的聲明后有緊接著一段靜態(tài)代碼塊:

 private static native void registerNatives();
 static {
  registerNatives();
 }

3.protected native Object clone() throws CloneNotSupportedException;

clone()方法又是一個被聲明為native的方法,因此,我們知道了clone()方法并不是Java的原生方法,具體的實現(xiàn)是有C/C++完成的。clone英文翻譯為"克隆",其目的是創(chuàng)建并返回此對象的一個副本。形象點理解,這有一輛寶馬汽車,你看著不錯,想要個一模一樣的。你調(diào)用此方法即可像變魔術一樣變出一輛一模一樣的寶馬出來。配置一樣,長相一樣。但從此刻起,原來的那輛寶馬如果進行了新的裝飾,與你克隆出來的這輛寶馬沒有任何關系了。你克隆出來的對象變不變完全在于你對克隆出來的寶馬有沒有進行過什么操作了。Java術語表述為:clone函數(shù)返回的是一個引用,指向的是新的clone出來的對象,此對象與原對象分別占用不同的堆空間。
明白了clone的含義后,接下來看看如果調(diào)用clone()函數(shù)對象進行此克隆操作。

首先看一下下面的這個例子:

 package com.bjpowernode.test;
 import com.corn.Person;
 public class ObjectTest {
  public static void main(String[] args) {
   Object o1 = new Object();
   // The method clone() from the type Object is not visible
  Object clone = o1.clone();
  }
 }

例子很簡單,在main()方法中,new一個Oject對象后,想直接調(diào)用此對象的clone方法克隆一個對象,但是出現(xiàn)錯誤提示:"The method clone() from the type Object is not visible"
why? 根據(jù)提示,第一反應是ObjectTest類中定義的Oject對象無法訪問其clone()方法?;氐絆bject類中clone()方法的定義,可以看到其被聲明為protected,估計問題就在這上面了,protected修飾的屬性或方法表示:在同一個包內(nèi)或者不同包的子類可以訪問。顯然,Object類與ObjectTest類在不同的包中,但是ObjectTest繼承自Object,是Object類的子類,于是,現(xiàn)在卻出現(xiàn)子類中通過Object引用不能訪問protected方法,原因在于對"不同包中的子類可以訪問"沒有正確理解。

"不同包中的子類可以訪問",是指當兩個類不在同一個包中的時候,繼承自父類的子類內(nèi)部且主調(diào)(調(diào)用者)為子類的引用時才能訪問父類用protected修飾的成員(屬性/方法)。 在子類內(nèi)部,主調(diào)為父類的引用時并不能訪問此protected修飾的成員。?。╯uper關鍵字除外)

于是,上例改成如下形式,我們發(fā)現(xiàn),可以正常編譯:

package com.bjpowernode.test;
 public class ObjectTest {
  public static void main(String[] args) {
   ObjectTest ot1 = new ObjectTest();
   try {
   ObjectTest ot2 = (ObjectTest) ot1.clone();
   } catch (CloneNotSupportedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 } 

是的,因為此時的主調(diào)已經(jīng)是子類的引用了。

上述代碼在運行過程中會拋出"java.lang.CloneNotSupportedException",表明clone()方法并未正確執(zhí)行完畢,問題的原因在與Java中的語法規(guī)定:

clone()的正確調(diào)用是需要實現(xiàn)Cloneable接口,如果沒有實現(xiàn)Cloneable接口,并且子類直接調(diào)用Object類的clone()方法,則會拋出CloneNotSupportedException異常。

Cloneable接口僅是一個表示接口,接口本身不包含任何方法,用來指示Object.clone()可以合法的被子類引用所調(diào)用。

于是,上述代碼改成如下形式,即可正確指定clone()方法以實現(xiàn)克隆。

 package com.bjpowernode.test;
 public class ObjectTest implements Cloneable {
  public static void main(String[] args) {
   ObjectTest ot1 = new ObjectTest();
   try {
    ObjectTest ot2 = (ObjectTest) ot1.clone();
   System.out.println("ot2:" + ot2);
   } catch (CloneNotSupportedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

4.public final native Class<&#63;> getClass();

getClass()也是一個native方法,返回的是此Object對象的類對象/運行時類對象Class<&#63;>。效果與Object.class相同。

首先解釋下"類對象"的概念:在Java中,類是是對具有一組相同特征或行為的實例的抽象并進行描述,對象則是此類所描述的特征或行為的具體實例。作為概念層次的類,其本身也具有某些共同的特性,如都具有類名稱、由類加載器去加載,都具有包,具有父類,屬性和方法等。于是,Java中有專門定義了一個類,Class,去描述其他類所具有的這些特性,因此,從此角度去看,類本身也都是屬于Class類的對象。為與經(jīng)常意義上的對象相區(qū)分,在此稱之為"類對象"。

5.public boolean equals(Object obj);

==與equals在Java中經(jīng)常被使用,大家也都知道==與equals的區(qū)別:==表示的是變量值完成相同(對于基礎類型,地址中存儲的是值,引用類型則存儲指向?qū)嶋H對象的地址);
equals表示的是對象的內(nèi)容完全相同,此處的內(nèi)容多指對象的特征/屬性。

實際上,上面說法是不嚴謹?shù)?,更多的只是常見于String類中。首先看一下Object類中關于equals()方法的定義:

 public boolean equals(Object obj) {
  return (this == obj);
 }

由此可見,Object原生的equals()方法內(nèi)部調(diào)用的正是==,與==具有相同的含義。既然如此,為什么還要定義此equals()方法?

equlas()方法的正確理解應該是:判斷兩個對象是否相等。那么判斷對象相等的標尺又是什么?

如上,在object類中,此標尺即為==。當然,這個標尺不是固定的,其他類中可以按照實際的需要對此標尺含義進行重定義。如String類中則是依據(jù)字符串內(nèi)容是否相等來重定義了此標尺含義。如此可以增加類的功能型和實際編碼的靈活性。當然了,如果自定義的類沒有重寫equals()方法來重新定義此標尺,那么默認的將是其父類的equals(),直到object基類。
如下場景的實際業(yè)務需求,對于User bean,由實際的業(yè)務需求可知當屬性uid相同時,表示的是同一個User,即兩個User對象相等。則可以重寫equals以重定義User對象相等的標尺。

package com.bjpowernode.test;
 public class User {
  private int uid;
  private String name;
  private int age;
  public int getUid() {
   return uid;
  }
  public void setUid(int uid) {
   this.uid = uid;
  }
  protected String getName() {
   return name;
  }
  public void setName(String name) {
   this.name = name;
  }
  public int getAge() {
   return age;
  }
  public void setAge(int age) {
   this.age = age;
  }
  @Override
  public boolean equals(Object obj) {
   if (obj == null || !(obj instanceof User)) {
    return false;
   }
   if (((User) obj).getUid() == this.getUid()) {
    return true;
   }
   return false;
  }
 }

 package com.bjpowernode.test;
 public class ObjectTest implements Cloneable {
  public static void main(String[] args) {
   User u1 = new User();
   u1.setUid(111);
   u1.setName("張三");
   User u2 = new User();
   u2.setUid(111);
   u2.setName("張三豐"); 
   System.out.println(u1.equals(u2)); //返回true
  }
 }

ObjectTest中打印出true,因為User類定義中重寫了equals()方法,這很好理解,很可能張三是一個人小名,張三豐才是其大名,判斷這兩個人是不是同一個人,這時只用判斷uid是否相同即可。

如上重寫equals方法表面上看上去是可以了,實則不然。因為它破壞了Java中的約定:重寫equals()方法必須重寫hasCode()方法。 

6.public native int hashCode();

hashCode()方法返回一個整形數(shù)值,表示該對象的哈希碼值。

hashCode()具有如下約定:

1. 在Java應用程序程序執(zhí)行期間,對于同一對象多次調(diào)用hashCode()方法時,其返回的哈希碼是相同的,前提是將對象進行equals比較時所用的標尺信息未做修改。在Java應用程序的一次執(zhí)行到另外一次執(zhí)行,同一對象的hashCode()返回的哈希碼無須保持一致;

2. 如果兩個對象相等(依據(jù):調(diào)用equals()方法),那么這兩個對象調(diào)用hashCode()返回的哈希碼也必須相等;

3. 反之,兩個對象調(diào)用hasCode()返回的哈希碼相等,這兩個對象不一定相等。

即嚴格的數(shù)學邏輯表示為: 兩個對象相等 <=>  equals()相等  => hashCode()相等。因此,重寫equlas()方法必須重寫hashCode()方法,以保證此邏輯嚴格成立,同時可以推理出:hasCode()不相等 => equals()不相等 <=> 兩個對象不相等。

可能有人在此產(chǎn)生疑問:既然比較兩個對象是否相等的唯一條件(也是沖要條件)是equals,那么為什么還要弄出一個hashCode(),并且進行如此約定,弄得這么麻煩?

其實,這主要體現(xiàn)在hashCode()方法的作用上,其主要用于增強哈希表的性能。

以集合類中,以Set為例,當新加一個對象時,需要判斷現(xiàn)有集合中是否已經(jīng)存在與此對象相等的對象,如果沒有hashCode()方法,需要將Set進行一次遍歷,并逐一用equals()方法判斷兩個對象是否相等,此種算法時間復雜度為o(n)。通過借助于hasCode方法,先計算出即將新加入對象的哈希碼,然后根據(jù)哈希算法計算出此對象的位置,直接判斷此位置上是否已有對象即可。(注:Set的底層用的是Map的原理實現(xiàn))

在此需要糾正一個理解上的誤區(qū):對象的hashCode()返回的不是對象所在的物理內(nèi)存地址。甚至也不一定是對象的邏輯地址,hashCode()相同的兩個對象,不一定相等,換言之,不相等的兩個對象,hashCode()返回的哈希碼可能相同。

因此,在上述代碼中,重寫了equals()方法后,需要重寫hashCode()方法。

package com.bjpowernode.test;
 public class User {
  private int uid;
  private String name;
  private int age;
  public int getUid() {
   return uid;
  }
  public void setUid(int uid) {
   this.uid = uid;
  }
  protected String getName() {
   return name;
  }
  public void setName(String name) {
   this.name = name;
  }
  public int getAge() {
   return age;
  }
  public void setAge(int age) {
   this.age = age;
  }
  @Override
  public boolean equals(Object obj) {
   if (obj == null || !(obj instanceof User)) {
    return false;
   }
   if (((User) obj).getUid() == this.getUid()) {
    return true;
   }
   return false;
  }
  @Override
  public int hashCode() {
   int result = 17;
   result = 31 * result + this.getUid();
   return result;
  }
 }

注:上述hashCode()的重寫中出現(xiàn)了result*31,是因為result*31 = (result<<5) - result。之所以選擇31,是因為左移運算和減運算計算效率遠大于乘法運算。當然,也可以選擇其他數(shù)字。 

7.public String toString();

toString()方法返回該對象的字符串表示。先看一下Object中的具體方法體:

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

toString()方法相信大家都經(jīng)常用到,即使沒有顯式調(diào)用,但當我們使用System.out.println(obj)時,其內(nèi)部也是通過toString()來實現(xiàn)的。

getClass()返回對象的類對象,getClassName()以String形式返回類對象的名稱(含包名)。Integer.toHexString(hashCode())則是以對象的哈希碼為實參,以16進制無符號整數(shù)形式返回此哈希碼的字符串表示形式。
如上例中的u1的哈希碼是638,則對應的16進制為27e,調(diào)用toString()方法返回的結(jié)果為:com.bjpowernode.test.User@27e。

因此:toString()是由對象的類型和其哈希碼唯一確定,同一類型但不相等的兩個對象分別調(diào)用toString()方法返回的結(jié)果可能相同。

8/9/10/11/12. wait(...) / notify() / notifyAll()

一說到wait(...) / notify() | notifyAll()幾個方法,首先想到的是線程。確實,這幾個方法主要用于java多線程之間的協(xié)作。先具體看下這幾個方法的主要含義:
wait():調(diào)用此方法所在的當前線程等待,直到在其他線程上調(diào)用此方法的主調(diào)(某一對象)的notify()/notifyAll()方法。

wait(long timeout)/wait(long timeout, int nanos):調(diào)用此方法所在的當前線程等待,直到在其他線程上調(diào)用此方法的主調(diào)(某一對象)的notisfy()/notisfyAll()方法,或超過指定的超時時間量。
notify()/notifyAll():喚醒在此對象監(jiān)視器上等待的單個線程/所有線程。

wait(...) / notify() | notifyAll()一般情況下都是配套使用。下面來看一個簡單的例子:

 package com.bjpowernode.test;
 public class ThreadTest {
  /**
  * @param args
  */
  public static void main(String[] args) {
   // TODO Auto-generated method stub
   MyRunnable r = new MyRunnable();
   Thread t = new Thread(r);
   t.start();
   synchronized (r) {
    try {
     System.out.println("main thread 等待t線程執(zhí)行完");
     r.wait();
     System.out.println("被notity喚醒,得以繼續(xù)執(zhí)行");
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     System.out.println("main thread 本想等待,但被意外打斷了");
    }
    System.out.println("線程t執(zhí)行相加結(jié)果" + r.getTotal());
   }
  }
 }
 class MyRunnable implements Runnable {
  private int total;
  @Override
  public void run() {
   // TODO Auto-generated method stub
   synchronized (this) {
    System.out.println("Thread name is:" + Thread.currentThread().getName());
   for (int i = 0; i < 10; i++) {
     total += i;
    }
    notify();
    System.out.println("執(zhí)行notif后同步代碼塊中依然可以繼續(xù)執(zhí)行直至完畢");
   }
   System.out.println("執(zhí)行notif后且同步代碼塊外的代碼執(zhí)行時機取決于線程調(diào)度");
  }
  public int getTotal() {
   return total;
  }
 }

運行結(jié)果為:

1 main thread 等待t線程執(zhí)行完

2 Thread name is:Thread-0

3 執(zhí)行notif后同步代碼塊中依然可以繼續(xù)執(zhí)行直至完畢

4 執(zhí)行notif后且同步代碼塊外的代碼執(zhí)行時機取決于線程調(diào)度  //此行輸出位置有具體的JVM線程調(diào)度決定,有可能最后執(zhí)行

5 被notity喚醒,得以繼續(xù)執(zhí)行

6 線程t執(zhí)行相加結(jié)果45

既然是作用于多線程中,為什么卻是Object這個基類所具有的方法?原因在于理論上任何對象都可以視為線程同步中的監(jiān)聽器,且wait(...)/notify()|notifyAll()方法只能在同步代碼塊中才能使用。
 從上述例子的輸出結(jié)果中可以得出如下結(jié)論:

1、wait(...)方法調(diào)用后當前線程將立即阻塞,且適當其所持有的同步代碼塊中的鎖,直到被喚醒或超時或打斷后且重新獲取到鎖后才能繼續(xù)執(zhí)行;

2、notify()/notifyAll()方法調(diào)用后,其所在線程不會立即釋放所持有的鎖,直到其所在同步代碼塊中的代碼執(zhí)行完畢,此時釋放鎖,因此,如果其同步代碼塊后還有代碼,其執(zhí)行則依賴于JVM的線程調(diào)度。
在Java源碼中,可以看到wait()具體定義如下:

 public final void wait() throws InterruptedException {
  wait(0);
 }

且wait(long timeout, int nanos)方法定義內(nèi)部實質(zhì)上也是通過調(diào)用wait(long timeout)完成。而wait(long timeout)是一個native方法。因此,wait(...)方法本質(zhì)上都是native方式實現(xiàn)。
notify()/notifyAll()方法也都是native方法。

Java中線程具有較多的知識點,是一塊比較大且重要的知識點。后期會有博文專門針對Java多線程作出詳細總結(jié)。此處不再細述。

13. protected void finalize();

finalize方法主要與Java垃圾回收機制有關。首先我們看一下finalized方法在Object中的具體定義:

 protected void finalize() throws Throwable { }

我們發(fā)現(xiàn)Object類中finalize方法被定義成一個空方法,為什么要如此定義呢?finalize方法的調(diào)用時機是怎么樣的呢?

首先,Object中定義finalize方法表明Java中每一個對象都將具有finalize這種行為,其具體調(diào)用時機在:JVM準備對此對形象所占用的內(nèi)存空間進行垃圾回收前,將被調(diào)用。由此可以看出,此方法并不是由我們主動去調(diào)用的(雖然可以主動去調(diào)用,此時與其他自定義方法無異)。

看完上述內(nèi)容,你們對深入淺析Java中的Object類有進一步的了解嗎?如果還想了解更多知識或者相關內(nèi)容,請關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

網(wǎng)站題目:深入淺析Java中的Object類
轉(zhuǎn)載來源:http://aaarwkj.com/article36/iijgsg.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設、網(wǎng)站制作、網(wǎng)站排名、軟件開發(fā)網(wǎng)頁設計公司、網(wǎng)站設計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站
蜜桃国产精品视频网站| 97精品国产高清在线| 久草热不卡的av在线| 久久久之久亚州精品露出| 精品人妻二区中文字幕| 久久婷婷国产综合精品青草| 亚洲一二三无人区是什么| 九九九热在线观看视频| 久久99久久久国产精品| 日本三级黄色免费的网站| 欧美午夜福利在线视频| av中文字幕在线电影| 在线观看91精品国产秒播| 蜜桃网站视频免费观看| 熟女人妻视频一区二区| 精品欧美熟妇高潮喷水特黄| 91人妻精品丰满少妇区| 亚洲欧美日韩精品二区| 四虎在线观看最新免费| 久久久精品人妻免费网站| 邻居少妇扒开腿让我爽了一夜| 日本成熟亚洲中文字幕的| 男人的天堂久久精品激情| 人人妻人人澡人人爽久久av| 日韩一区二区电影在线| 国产真人免费作爱视频网站| 91精品国产在线观看| 午夜福利在线视频观看| 粉嫩极品国产在线观看| 日韩三级在线观看av| 成人黄片免费在线播放| 亚洲欧洲精品专线九九| 欧美 国产 综合 日韩| 亚洲精品一区久久狠狠欧美| 人妻有码中文字幕在线| 一本久道久久综合久久鬼色| 亚洲av网站女性向在线观看| 欧美日韩久久亚洲精品| 亚洲自偷精品视频自拍| 亚洲激情在线观看一区| 久久久人妻91久久久久|