Java源码之Object

Posted mike11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
 
  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. }  
  12. class B extends A  
  13. {  
  14.   
  15. }  


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



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.            
  7.          System.out.println(a1);  
  8.          a1.setAge(11);  
  9.          a1.setName("big pig");  
  10.          System.out.println(a1.age + ":" + a1.name);  
  11.            
  12.          System.out.println(a2);  
  13.          System.out.println(a2.age + ":" + a2.name);  
  14.            
  15.      }  
  16.    
  17.  }  
  18.    
  19.  class Animal implements Cloneable{  
  20.      int age;  
  21.      String name;  
  22.    
  23.      Animal(int age, String name) {  
  24.          this.age = age;  
  25.          this.name = name;  
  26.      }  
  27.    
  28.      public Animal clone() {  
  29.          Animal o = null;  
  30.    
  31.          try {  
  32.              o = (Animal) super.clone();  
  33.          } catch (CloneNotSupportedException e) {  
  34.              e.printStackTrace();  
  35.          }  
  36.    
  37.          return o;  
  38.      }  
  39.    
  40.      public int getAge() {  
  41.          return age;  
  42.      }  
  43.    
  44.      public void setAge(int age) {  
  45.          this.age = age;  
  46.      }  
  47.    
  48.      public String getName() {  
  49.          return name;  
  50.      }  
  51.      public void setName(String name) {  
  52.          this.name = name;  
  53.      }  
  54. }  


 

"深复制"时,需要将共同关联的引用也复制完全看示例

 

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


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.   
  7.         if (nanos < 0 || nanos > 999999) {  
  8.             throw new IllegalArgumentException(  
  9.                                 "nanosecond timeout value out of range");  
  10.         }  
  11.   
  12.         if (nanos > 0) {  
  13.             timeout++;  
  14.         }  
  15.   
  16.         wait(timeout);  
  17.     }  

 

 

13.protected void finalize()

 

[java] view plain copy
 
  1. /*当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。*/      
  2.    protected void finalize() throws Throwable { }  

垃圾回收器在认为该对象是垃圾对象的时候会调用该方法。子类可以通过重写该方法来达到资源释放的目的。 
在方法调用过程中出现的异常会被忽略且方法调用会被终止。 
任何对象的该方法只会被调用一次。  

三丶参看文章
Object类源码解析
【java基础之jdk源码】Object

 

四丶相关面试题

【码农每日一题】Java equals 与 hashCode 相关面试题

以上是关于Java源码之Object的主要内容,如果未能解决你的问题,请参考以下文章

死磕 java集合之ConcurrentHashMap源码分析

死磕 java集合之ConcurrentHashMap源码分析

Java并发之AQS源码分析

死磕 java同步系列之CountDownLatch源码解析

Java源码之String

源码:Java集合源码之:哈希表