1. 程式人生 > >Java源碼之Object

Java源碼之Object

img modifying 垃圾回收 others cti 一起 繼續 應用程序 情況

本文出自:http://blog.csdn.net/dt235201314/article/details/78318399

一丶概述

JAVA中所有的類都繼承自Object類,就從Object作為源碼解析的開始。

二丶常見方法

技術分享

註: 以上綠色方法為 非native方法 粉色方法為 native方法)

什麽是native方法?

native關鍵字標識的java方法為本地方法,底層是有c/c++編寫的程序編譯後dll文件,java加載dll文件後,可用通過本地方法調用dll中函數,如有疑問可用參考JNI使用方式。

什麽是JNI方法?

向東是底層,向西是應用,咱們先一路向西。向東參考:JNI方法使用

1.Object():默認構造函數(源碼無系統默認提供)

2.void registerNatives()

[java] view plain copy
  1. /* 一個本地方法,具體是用C(C++)在DLL中實現的,然後通過JNI調用。*/
  2. private static native void registerNatives();
  3. /* 對象初始化時自動調用此方法*/
  4. static {
  5. registerNatives();
  6. }

3.final getClass()

[java] view plain copy
  1. /* 返回此 Object 的運行時類。*/
  2. public final native Class<?> getClass();

例:

[java] view plain copy
  1. public class tests
  2. {
  3. public static void main(String[] args)
  4. {
  5. A te = new B();
  6. System.out.println(te.getClass());
  7. }
  8. }
  9. class A{
  10. }
  11. class B extends A
  12. {
  13. }


運行結果:class B

A類的引用,但是運行時te這個對象的實際類是B。

4.int hashCode()方法

[java] view plain copy
  1. /*
  2. hashCode 的常規協定是:
  3. 1.在應用程序執行期間,如果一個對象用於equals()方法的屬性沒有被修改的話,
  4. 那麽要保證對該對象多次返回的hashcode值要相等。
  5. 2.如果2個對象通過equals()方法判斷的結果為true,那麽要保證二者的hashcode值相等。
  6. 3.如果2個對象通過equals()方法判斷的結果為false,那麽對二者hashcode值是否相等並沒有明確要求。
  7. 如果不相等,那麽能夠提升散列表的性能。
  8. */
  9. public native int hashCode();

實際計算方法:

[java] view plain copy
  1. public int hashCode() {
  2. int h = hash;
  3. if (h == 0 && value.length > 0) {
  4. char val[] = value;
  5. for (int i = 0; i < value.length; i++) {
  6. h = 31 * h + val[i];
  7. }
  8. hash = h;
  9. }
  10. return h;
  11. }

5.boolean equals(Object obj)

[java] view plain copy
  1. public boolean equals(Object obj) {
  2. return (this == obj);
  3. }


從這裏我們可以看到,equals(obj)方法最根本的實現就是‘==’,因此對於一些自定義類,如果沒有重寫hashcode()方法和equals()方法的話,利用‘==’和equals()方法比較的結果是一樣的。對於‘==’比較的是地址,equals()方法比較的是內容這種說法,是片面的。(雖然在最常用的String類中是這樣的)。

equal方法常被重寫

例:String(先比較String對象內存地址相同,若相同則返回true,否則判斷String對象對應字符的內容是否相等,若相等則返回true)

[java] view plain copy
  1. public boolean equals(Object anObject) {
  2. if (this == anObject) {
  3. return true;
  4. }
  5. if (anObject instanceof String) {
  6. String anotherString = (String)anObject;
  7. int n = value.length;
  8. if (n == anotherString.value.length) {
  9. char v1[] = value;
  10. char v2[] = anotherString.value;
  11. int i = 0;
  12. while (n-- != 0) {
  13. if (v1[i] != v2[i])
  14. return false;
  15. i++;
  16. }
  17. return true;
  18. }
  19. }
  20. return false;
  21. }

6.clone()

[java] view plain copy
  1. /*本地CLONE方法,用於對象的復制。*/
  2. protected native Object clone() throws CloneNotSupportedException;

一起看下native方法 位於openjdk\hotspot\src\share\vm\prims\jvm.cpp中 JVM_Clone的實現 片段

[java] view plain copy
  1. JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
  2. JVMWrapper("JVM_Clone");
  3. Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  4. const KlassHandle klass (THREAD, obj->klass());
  5. JvmtiVMObjectAllocEventCollector oam;
  6. #ifdef ASSERT
  7. // Just checking that the cloneable flag is set correct
  8. if (obj->is_javaArray()) {
  9. guarantee(klass->is_cloneable(), "all arrays are cloneable");
  10. } else {
  11. guarantee(obj->is_instance(), "should be instanceOop");
  12. bool cloneable = klass->is_subtype_of(SystemDictionary::Cloneable_klass());
  13. guarantee(cloneable == klass->is_cloneable(), "incorrect cloneable flag");
  14. }
  15. #endif
  16. // Check if class of obj supports the Cloneable interface.
  17. // All arrays are considered to be cloneable (See JLS 20.1.5)
  18. if (!klass->is_cloneable()) {
  19. ResourceMark rm(THREAD);
  20. THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
  21. }
  22. // Make shallow object copy
  23. const int size = obj->size();
  24. oop new_obj = NULL;
  25. if (obj->is_javaArray()) {
  26. const int length = ((arrayOop)obj())->length();
  27. new_obj = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL);
  28. } else {
  29. new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);
  30. }
  31. // 4839641 (4840070): We must do an oop-atomic copy, because if another thread
  32. // is modifying a reference field in the clonee, a non-oop-atomic copy might
  33. // be suspended in the middle of copying the pointer and end up with parts
  34. // of two different pointers in the field. Subsequent dereferences will crash.
  35. // 4846409: an oop-copy of objects with long or double fields or arrays of same
  36. // won‘t copy the longs/doubles atomically in 32-bit vm‘s, so we copy jlongs instead
  37. // of oops. We know objects are aligned on a minimum of an jlong boundary.
  38. // The same is true of StubRoutines::object_copy and the various oop_copy
  39. // variants, and of the code generated by the inline_native_clone intrinsic.
  40. assert(MinObjAlignmentInBytes >= BytesPerLong, "objects misaligned");
  41. Copy::conjoint_jlongs_atomic((jlong*)obj(), (jlong*)new_obj,
  42. (size_t)align_object_size(size) / HeapWordsPerLong);
  43. // Clear the header
  44. new_obj->init_mark();
  45. // Store check (mark entire object and let gc sort it out)
  46. BarrierSet* bs = Universe::heap()->barrier_set();
  47. assert(bs->has_write_region_opt(), "Barrier set does not have write_region");
  48. bs->write_region(MemRegion((HeapWord*)new_obj, size));
  49. // Caution: this involves a java upcall, so the clone should be
  50. // "gc-robust" by this stage.
  51. if (klass->has_finalizer()) {
  52. assert(obj->is_instance(), "should be instanceOop");
  53. new_obj = instanceKlass::register_finalizer(instanceOop(new_obj), CHECK_NULL);
  54. }
  55. return JNIHandles::make_local(env, oop(new_obj));
  56. JVM_END

看不懂,這裏參考大神講解

隱含意思:數組類型默認可以直接克隆,而其他對象實現clone需要先實現Cloneable接口,否則拋出CloneNotSupportedException異常
問題1:對象的創建有多中方式,類似 new 、getInstance、clone等 clone有什麽好處?
問題2:對象調用clone方法生成的對象 和 原對象是否還有什麽關聯關系?
問題3 : 對象clone存在 “淺復制”、“深復制”概念,怎麽區分?
帶著這3個問題,理解Object clone方法:
1、一般native方法比java中非native方法執行效率高 ,看示例

[java] view plain copy
  1. public class ObjectCloneTest1 {
  2. static final int N = 100000;
  3. public static void main(String[] args) {
  4. final Date date = new Date();
  5. {
  6. final long startTime = System.currentTimeMillis();
  7. for (int i = 0; i < N; i++) {
  8. Date date2 = (Date) date.clone();
  9. }
  10. final long endTime = System.currentTimeMillis();
  11. System.out.println("clone:" + (endTime - startTime) + "ms");
  12. }
  13. {
  14. final long startTime = System.currentTimeMillis();
  15. for (int i = 0; i < N; i++) {
  16. final Calendar cal = Calendar.getInstance();
  17. cal.setTime(date);
  18. final Date date2 = cal.getTime();
  19. }
  20. final long endTime = System.currentTimeMillis();
  21. System.out.println("Calender.setTime:" + (endTime - startTime) + "ms");
  22. }
  23. }
  24. }

技術分享

2、clone生成的新對象與原對象的關系,需要區別2個對象建是否存在相同的引用或對應的內存地址是否存在共用情況,若存在則 該次clone為 “淺復制”,否則為“深復制”, 而且Object的clone方法是屬於 “淺復制”,看示例

[java] view plain copy
  1. public class ObjectCloneTest2 {
  2. public static void main(String[] args) {
  3. Animal a1 = new Animal(1, "pig");
  4. Animal a2 = (Animal) a1.clone();
  5. System.out.println(a1.getName() == a2.getName() ? "淺復制" : "深復制");
  6. System.out.println(a1);
  7. a1.setAge(11);
  8. a1.setName("big pig");
  9. System.out.println(a1.age + ":" + a1.name);
  10. System.out.println(a2);
  11. System.out.println(a2.age + ":" + a2.name);
  12. }
  13. }
  14. class Animal implements Cloneable{
  15. int age;
  16. String name;
  17. Animal(int age, String name) {
  18. this.age = age;
  19. this.name = name;
  20. }
  21. public Animal clone() {
  22. Animal o = null;
  23. try {
  24. o = (Animal) super.clone();
  25. } catch (CloneNotSupportedException e) {
  26. e.printStackTrace();
  27. }
  28. return o;
  29. }
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36. public String getName() {
  37. return name;
  38. }
  39. public void setName(String name) {
  40. this.name = name;
  41. }
  42. }


技術分享

"深復制"時,需要將共同關聯的引用也復制完全看示例

[java] view plain copy
  1. public class ObjectCloneTest3 {
  2. public static void main(String[] args) {
  3. Person p1 = new Person(10, "ll", new Race("yellow", "Asia"));
  4. Person p2 = (Person) p1.clone();
  5. System.out.println(p1.getRace() == p2.getRace());
  6. System.out.println(p1.getTestArray() == p2.getTestArray());
  7. }
  8. }
  9. class Person implements Cloneable {
  10. int age;
  11. String name;
  12. Race race;
  13. int[] testArray = { 1, 23, 5, 6, 0 };
  14. Person(int age, String name, Race race) {
  15. this.age = age;
  16. this.name = name;
  17. this.race = race;
  18. }
  19. public Person clone() {
  20. Person o = null;
  21. try {
  22. o = (Person) super.clone();
  23. o.setRace(this.race.clone());
  24. o.setTestArray(testArray.clone());
  25. } catch (CloneNotSupportedException e) {
  26. e.printStackTrace();
  27. }
  28. return o;
  29. }
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36. public String getName() {
  37. return name;
  38. }
  39. public void setName(String name) {
  40. this.name = name;
  41. }
  42. public Race getRace() {
  43. return race;
  44. }
  45. public void setRace(Race race) {
  46. this.race = race;
  47. }
  48. public void setTestArray(int[] testArray) {
  49. this.testArray = testArray;
  50. }
  51. public int[] getTestArray() {
  52. return testArray;
  53. }
  54. }
  55. class Race implements Cloneable {
  56. String color; // 顏色
  57. String distribution; // 分布
  58. public Race(String color, String distribution) {
  59. super();
  60. this.color = color;
  61. this.distribution = distribution;
  62. }
  63. public Race clone() throws CloneNotSupportedException {
  64. return (Race) super.clone();
  65. }
  66. }


false

false

7.toString()

[java] view plain copy
  1. /*返回該對象的字符串表示。非常重要的方法*/
  2. public String toString() {
  3. return getClass().getName() + "@" + Integer.toHexString(hashCode());
  4. }

默認返回對象的名稱及引用地址,但一般被子類重寫用於說明子類相關屬性值描述

8.final notify()

[java] view plain copy
  1. /*不能被重寫,喚醒在此對象監視器上等待的單個線程。*/
  2. public final native void notify();

9.final notifyAll()

[java] view plain copy
  1. /*喚醒在此對象監視器上等待的所有線程。*/
  2. public final native void notifyAll();

10.final void wait()方法

[java] view plain copy
  1. /*在其他線程調用此對象的 notify() 方法或 notifyAll() 方法前,導致當前線程等待。換句話說,此方法的行為就好像它僅執行 wait(0) 調用一樣。
  2. 當前線程必須擁有此對象監視器。該線程發布對此監視器的所有權並等待,直到其他線程通過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。然後該線程將等到重新獲得對監視器的所有權後才能繼續執行。*/
  3. public final void wait() throws InterruptedException {
  4. wait(0);
  5. }

11.final native void wait(long timeout)

[java] view plain copy
  1. /*在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,導致當前線程等待。*/
  2. public final native void wait(long timeout) throws InterruptedException;

該方法使當前線程等待,直到另外一個線程調用該對象的notify或notifyAll方法,或者等待時間已到,當前線程才會從等待池移到運行池。
如果在wait之前或者wait的時候,當前線程被中斷了,那麽直到該線程被恢復的時候才會拋出中斷異常(InterruptedException)

12.final void wait(long timeout,int nanos)

[java] view plain copy
  1. /* 在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量前,導致當前線程等待。*/
  2. public final void wait(long timeout, int nanos) throws InterruptedException {
  3. if (timeout < 0) {
  4. throw new IllegalArgumentException("timeout value is negative");
  5. }
  6. if (nanos < 0 || nanos > 999999) {
  7. throw new IllegalArgumentException(
  8. "nanosecond timeout value out of range");
  9. }
  10. if (nanos > 0) {
  11. timeout++;
  12. }
  13. wait(timeout);
  14. }

13.protected void finalize()

[java] view plain copy
  1. /*當垃圾回收器確定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。*/
  2. protected void finalize() throws Throwable { }

垃圾回收器在認為該對象是垃圾對象的時候會調用該方法。子類可以通過重寫該方法來達到資源釋放的目的。
在方法調用過程中出現的異常會被忽略且方法調用會被終止。
任何對象的該方法只會被調用一次。

三丶參看文章
Object類源碼解析
【java基礎之jdk源碼】Object

四丶相關面試題

【碼農每日一題】Java equals 與 hashCode 相關面試題

Java源碼之Object