Java源碼之Object
本文出自: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
- /* 一個本地方法,具體是用C(C++)在DLL中實現的,然後通過JNI調用。*/
- private static native void registerNatives();
- /* 對象初始化時自動調用此方法*/
- static {
- registerNatives();
- }
3.final getClass()
- /* 返回此 Object 的運行時類。*/
- public final native Class<?> getClass();
例:
[java] view plain copy
- public class tests
- {
- public static void main(String[] args)
- {
- A te = new B();
- System.out.println(te.getClass());
- }
- }
- class A{
- }
- class B extends A
- {
- }
運行結果:class B
A類的引用,但是運行時te這個對象的實際類是B。
4.int hashCode()方法
[java] view plain copy
- /*
- hashCode 的常規協定是:
- 1.在應用程序執行期間,如果一個對象用於equals()方法的屬性沒有被修改的話,
- 那麽要保證對該對象多次返回的hashcode值要相等。
- 2.如果2個對象通過equals()方法判斷的結果為true,那麽要保證二者的hashcode值相等。
- 3.如果2個對象通過equals()方法判斷的結果為false,那麽對二者hashcode值是否相等並沒有明確要求。
- 如果不相等,那麽能夠提升散列表的性能。
- */
- public native int hashCode();
實際計算方法:
[java] view plain copy
- public int hashCode() {
- int h = hash;
- if (h == 0 && value.length > 0) {
- char val[] = value;
- for (int i = 0; i < value.length; i++) {
- h = 31 * h + val[i];
- }
- hash = h;
- }
- return h;
- }
5.boolean equals(Object obj)
[java] view plain copy
- public boolean equals(Object obj) {
- return (this == obj);
- }
從這裏我們可以看到,equals(obj)方法最根本的實現就是‘==’,因此對於一些自定義類,如果沒有重寫hashcode()方法和equals()方法的話,利用‘==’和equals()方法比較的結果是一樣的。對於‘==’比較的是地址,equals()方法比較的是內容這種說法,是片面的。(雖然在最常用的String類中是這樣的)。
equal方法常被重寫
例:String(先比較String對象內存地址相同,若相同則返回true,否則判斷String對象對應字符的內容是否相等,若相等則返回true)
[java] view plain copy
- 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;
- }
6.clone()
[java] view plain copy
- /*本地CLONE方法,用於對象的復制。*/
- protected native Object clone() throws CloneNotSupportedException;
一起看下native方法 位於openjdk\hotspot\src\share\vm\prims\jvm.cpp中 JVM_Clone的實現 片段
[java] view plain copy- JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
- JVMWrapper("JVM_Clone");
- Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
- const KlassHandle klass (THREAD, obj->klass());
- JvmtiVMObjectAllocEventCollector oam;
- #ifdef ASSERT
- // Just checking that the cloneable flag is set correct
- if (obj->is_javaArray()) {
- guarantee(klass->is_cloneable(), "all arrays are cloneable");
- } else {
- guarantee(obj->is_instance(), "should be instanceOop");
- bool cloneable = klass->is_subtype_of(SystemDictionary::Cloneable_klass());
- guarantee(cloneable == klass->is_cloneable(), "incorrect cloneable flag");
- }
- #endif
- // Check if class of obj supports the Cloneable interface.
- // All arrays are considered to be cloneable (See JLS 20.1.5)
- if (!klass->is_cloneable()) {
- ResourceMark rm(THREAD);
- THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
- }
- // Make shallow object copy
- const int size = obj->size();
- oop new_obj = NULL;
- if (obj->is_javaArray()) {
- const int length = ((arrayOop)obj())->length();
- new_obj = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL);
- } else {
- new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);
- }
- // 4839641 (4840070): We must do an oop-atomic copy, because if another thread
- // is modifying a reference field in the clonee, a non-oop-atomic copy might
- // be suspended in the middle of copying the pointer and end up with parts
- // of two different pointers in the field. Subsequent dereferences will crash.
- // 4846409: an oop-copy of objects with long or double fields or arrays of same
- // won‘t copy the longs/doubles atomically in 32-bit vm‘s, so we copy jlongs instead
- // of oops. We know objects are aligned on a minimum of an jlong boundary.
- // The same is true of StubRoutines::object_copy and the various oop_copy
- // variants, and of the code generated by the inline_native_clone intrinsic.
- assert(MinObjAlignmentInBytes >= BytesPerLong, "objects misaligned");
- Copy::conjoint_jlongs_atomic((jlong*)obj(), (jlong*)new_obj,
- (size_t)align_object_size(size) / HeapWordsPerLong);
- // Clear the header
- new_obj->init_mark();
- // Store check (mark entire object and let gc sort it out)
- BarrierSet* bs = Universe::heap()->barrier_set();
- assert(bs->has_write_region_opt(), "Barrier set does not have write_region");
- bs->write_region(MemRegion((HeapWord*)new_obj, size));
- // Caution: this involves a java upcall, so the clone should be
- // "gc-robust" by this stage.
- if (klass->has_finalizer()) {
- assert(obj->is_instance(), "should be instanceOop");
- new_obj = instanceKlass::register_finalizer(instanceOop(new_obj), CHECK_NULL);
- }
- return JNIHandles::make_local(env, oop(new_obj));
- 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
- public class ObjectCloneTest1 {
- static final int N = 100000;
- public static void main(String[] args) {
- final Date date = new Date();
- {
- final long startTime = System.currentTimeMillis();
- for (int i = 0; i < N; i++) {
- Date date2 = (Date) date.clone();
- }
- final long endTime = System.currentTimeMillis();
- System.out.println("clone:" + (endTime - startTime) + "ms");
- }
- {
- final long startTime = System.currentTimeMillis();
- for (int i = 0; i < N; i++) {
- final Calendar cal = Calendar.getInstance();
- cal.setTime(date);
- final Date date2 = cal.getTime();
- }
- final long endTime = System.currentTimeMillis();
- System.out.println("Calender.setTime:" + (endTime - startTime) + "ms");
- }
- }
- }
2、clone生成的新對象與原對象的關系,需要區別2個對象建是否存在相同的引用或對應的內存地址是否存在共用情況,若存在則 該次clone為 “淺復制”,否則為“深復制”, 而且Object的clone方法是屬於 “淺復制”,看示例
[java] view plain copy
- public class ObjectCloneTest2 {
- public static void main(String[] args) {
- Animal a1 = new Animal(1, "pig");
- Animal a2 = (Animal) a1.clone();
- System.out.println(a1.getName() == a2.getName() ? "淺復制" : "深復制");
- System.out.println(a1);
- a1.setAge(11);
- a1.setName("big pig");
- System.out.println(a1.age + ":" + a1.name);
- System.out.println(a2);
- System.out.println(a2.age + ":" + a2.name);
- }
- }
- class Animal implements Cloneable{
- int age;
- String name;
- Animal(int age, String name) {
- this.age = age;
- this.name = name;
- }
- public Animal clone() {
- Animal o = null;
- try {
- o = (Animal) super.clone();
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return o;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
"深復制"時,需要將共同關聯的引用也復制完全看示例
[java] view plain copy
- public class ObjectCloneTest3 {
- public static void main(String[] args) {
- Person p1 = new Person(10, "ll", new Race("yellow", "Asia"));
- Person p2 = (Person) p1.clone();
- System.out.println(p1.getRace() == p2.getRace());
- System.out.println(p1.getTestArray() == p2.getTestArray());
- }
- }
- class Person implements Cloneable {
- int age;
- String name;
- Race race;
- int[] testArray = { 1, 23, 5, 6, 0 };
- Person(int age, String name, Race race) {
- this.age = age;
- this.name = name;
- this.race = race;
- }
- public Person clone() {
- Person o = null;
- try {
- o = (Person) super.clone();
- o.setRace(this.race.clone());
- o.setTestArray(testArray.clone());
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return o;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Race getRace() {
- return race;
- }
- public void setRace(Race race) {
- this.race = race;
- }
- public void setTestArray(int[] testArray) {
- this.testArray = testArray;
- }
- public int[] getTestArray() {
- return testArray;
- }
- }
- class Race implements Cloneable {
- String color; // 顏色
- String distribution; // 分布
- public Race(String color, String distribution) {
- super();
- this.color = color;
- this.distribution = distribution;
- }
- public Race clone() throws CloneNotSupportedException {
- return (Race) super.clone();
- }
- }
false
false
7.toString()
[java] view plain copy
- /*返回該對象的字符串表示。非常重要的方法*/
- public String toString() {
- return getClass().getName() + "@" + Integer.toHexString(hashCode());
- }
默認返回對象的名稱及引用地址,但一般被子類重寫用於說明子類相關屬性值描述
8.final notify()
[java] view plain copy
- /*不能被重寫,喚醒在此對象監視器上等待的單個線程。*/
- public final native void notify();
9.final notifyAll()
[java] view plain copy
- /*喚醒在此對象監視器上等待的所有線程。*/
- public final native void notifyAll();
10.final void wait()方法
[java] view plain copy
- /*在其他線程調用此對象的 notify() 方法或 notifyAll() 方法前,導致當前線程等待。換句話說,此方法的行為就好像它僅執行 wait(0) 調用一樣。
- 當前線程必須擁有此對象監視器。該線程發布對此監視器的所有權並等待,直到其他線程通過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。然後該線程將等到重新獲得對監視器的所有權後才能繼續執行。*/
- public final void wait() throws InterruptedException {
- wait(0);
- }
11.final native void wait(long timeout)
[java] view plain copy
- /*在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,導致當前線程等待。*/
- 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
- /* 在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量前,導致當前線程等待。*/
- public final void wait(long timeout, int nanos) throws InterruptedException {
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos > 0) {
- timeout++;
- }
- wait(timeout);
- }
13.protected void finalize()
[java] view plain copy
- /*當垃圾回收器確定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。*/
- protected void finalize() throws Throwable { }
垃圾回收器在認為該對象是垃圾對象的時候會調用該方法。子類可以通過重寫該方法來達到資源釋放的目的。
在方法調用過程中出現的異常會被忽略且方法調用會被終止。
任何對象的該方法只會被調用一次。
三丶參看文章
Object類源碼解析
【java基礎之jdk源碼】Object
四丶相關面試題
【碼農每日一題】Java equals 與 hashCode 相關面試題
Java源碼之Object