• 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方法 位于openjdkhotspotsrcsharevmprimsjvm.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 相关面试题

  • 相关阅读:
    Microsoft NNI入门
    【神经网络搜索】Efficient Neural Architecture Search
    Sphinx 快速构建工程文档
    Ubuntu16.04 Cuda11.1 Cudnn8.1 Tensorflow2.4 PyTorch1.7环境配置
    【CV中的Attention机制】ShuffleAttention
    【有趣的NAS】NAS-RL(ICLR2017)
    分类器
    将url下载到本地
    缓存管理器
    大数据数据结构-分类模型
  • 原文地址:https://www.cnblogs.com/uu5666/p/7779276.html
Copyright © 2020-2023  润新知