java基础之jdk源码Object

Posted cq_lala的地盘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基础之jdk源码Object相关的知识,希望对你有一定的参考价值。

最新在整体回归下java基础薄弱环节,以下为自己整理笔记,若有理解错误,请批评指正,谢谢。

java.lang.Object为java所有类的基类,所以一般的类都可用重写或直接使用Object下方法,以下为逻辑结构图,没有画类图

(注: 以上绿色方法为 非native方法  粉色方法为 native方法)

那么问题来了 :

1、what is a native object? 

  本人理解: native关键字标识的java方法为本地方法,底层是有c/c++编写的程序编译后dll文件,java加载dll文件后,

        可用通过本地方法调用dll中函数,如有疑问可用参考JNI使用方式,看参考:http://blog.csdn.net/yangjiali014/article/details/1633017

        以下为Object类对应openjdk\\jdk\\src\\share\\native\\java\\lang\\Object.c的源码片段1

1 static JNINativeMethod methods[] = {
2     {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
3     {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
4     {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
5     {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
6     {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
7 };

  网友见解:http://stackoverflow.com/questions/4568972/what-is-a-native-object

2、Why exist native method in Object Class?

  本人理解:涉及调用系统及考虑性能,使用c++或c实现更佳

  网友见解:http://stackoverflow.com/questions/10578764/why-are-hashcode-and-getclass-native-methods

       http://stackoverflow.com/questions/27224577/why-is-object-clone-native-in-java

  

现在按上图逐个方法讲讲理解:

  1、Object():默认构造函数

  2、 registerNatives(): 用于注册 代码片段1中的本地方法到jvm中

  java代码 片段2

1  private static native void registerNatives();
2  static {
3      registerNatives();
4  }

  对应c++代码 片段3

1 JNIEXPORT void JNICALL
2 Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
3 {
4     (*env)->RegisterNatives(env, cls,
5                             methods, sizeof(methods)/sizeof(methods[0]));
6 }

  3、final getClass():  (不能重写方法)方法说明中已经提示:Returns:The Class object that represents the runtime class of this object.

   来个简单例子 片段4

 1 package jdk;
 2 
 3 public class ObjectTest {
 4 
 5     public static void main(String[] args) {
 6         A a = new B();
 7         System.out.println(a.getClass());
 8     }
 9 }
10 
11 class A {
12     static{
13         System.out.println("初始化a");
14     }
15     
16 }
17 
18 class B extends A{
19     static{
20         System.out.println("初始化b");
21     }
22 }

  输出结果:

  可以看到getClass返回的为class B 非 A。

   4、hashCode():返回一个整数的值依赖于内部表示堆上的对象的指针

    方法说明:This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not           required by the Java™ programming language

  一起看下native方法 位于openjdk\\hotspot\\src\\share\\vm\\prims\\jvm.cpp中 JVM_IHashCode的实现 

1 JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
2   JVMWrapper("JVM_IHashCode");
3   // as implemented in the classic virtual machine; return 0 if object is NULL
4   return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
5 JVM_END

调用了ObjectSynchronizer::FastHashCode方法,位于openjdk\\hotspot\\src\\share\\vm\\runtime\\synchronizer.cpp中 第530行起

  1 static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  2   intptr_t value = 0 ;
  3   if (hashCode == 0) {
  4      // This form uses an unguarded global Park-Miller RNG,
  5      // so it\'s possible for two threads to race and generate the same RNG.
  6      // On MP system we\'ll have lots of RW access to a global, so the
  7      // mechanism induces lots of coherency traffic.
  8      value = os::random() ;
  9   } else
 10   if (hashCode == 1) {
 11      // This variation has the property of being stable (idempotent)
 12      // between STW operations.  This can be useful in some of the 1-0
 13      // synchronization schemes.
 14      intptr_t addrBits = intptr_t(obj) >> 3 ;
 15      value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
 16   } else
 17   if (hashCode == 2) {
 18      value = 1 ;            // for sensitivity testing
 19   } else
 20   if (hashCode == 3) {
 21      value = ++GVars.hcSequence ;
 22   } else
 23   if (hashCode == 4) {
 24      value = intptr_t(obj) ;
 25   } else {
 26      // Marsaglia\'s xor-shift scheme with thread-specific state
 27      // This is probably the best overall implementation -- we\'ll
 28      // likely make this the default in future releases.
 29      unsigned t = Self->_hashStateX ;
 30      t ^= (t << 11) ;
 31      Self->_hashStateX = Self->_hashStateY ;
 32      Self->_hashStateY = Self->_hashStateZ ;
 33      Self->_hashStateZ = Self->_hashStateW ;
 34      unsigned v = Self->_hashStateW ;
 35      v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
 36      Self->_hashStateW = v ;
 37      value = v ;
 38   }
 39 
 40   value &= markOopDesc::hash_mask;
 41   if (value == 0) value = 0xBAD ;
 42   assert (value != markOopDesc::no_hash, "invariant") ;
 43   TEVENT (hashCode: GENERATE) ;
 44   return value;
 45 }
 46 //
 47 intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
 48   if (UseBiasedLocking) {
 49     // NOTE: many places throughout the JVM do not expect a safepoint
 50     // to be taken here, in particular most operations on perm gen
 51     // objects. However, we only ever bias Java instances and all of
 52     // the call sites of identity_hash that might revoke biases have
 53     // been checked to make sure they can handle a safepoint. The
 54     // added check of the bias pattern is to avoid useless calls to
 55     // thread-local storage.
 56     if (obj->mark()->has_bias_pattern()) {
 57       // Box and unbox the raw reference just in case we cause a STW safepoint.
 58       Handle hobj (Self, obj) ;
 59       // Relaxing assertion for bug 6320749.
 60       assert (Universe::verify_in_progress() ||
 61               !SafepointSynchronize::is_at_safepoint(),
 62              "biases should not be seen by VM thread here");
 63       BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
 64       obj = hobj() ;
 65       assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
 66     }
 67   }
 68 
 69   // hashCode() is a heap mutator ...
 70   // Relaxing assertion for bug 6320749.
 71   assert (Universe::verify_in_progress() ||
 72           !SafepointSynchronize::is_at_safepoint(), "invariant") ;
 73   assert (Universe::verify_in_progress() ||
 74           Self->is_Java_thread() , "invariant") ;
 75   assert (Universe::verify_in_progress() ||
 76          ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
 77 
 78   ObjectMonitor* monitor = NULL;
 79   markOop temp, test;
 80   intptr_t hash;
 81   markOop mark = ReadStableMark (obj);
 82 
 83   // object should remain ineligible for biased locking
 84   assert (!mark->has_bias_pattern(), "invariant") ;
 85 
 86   if (mark->is_neutral()) {
 87     hash = mark->hash();              // this is a normal header
 88     if (hash) {                       // if it has hash, just return it
 89       return hash;
 90     }
 91     hash = get_next_hash(Self, obj);  // allocate a new hash code
 92     temp = mark->copy_set_hash(hash); // merge the hash code into header
 93     // use (machine word version) atomic operation to install the hash
 94     test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
 95     if (test == mark) {
 96       return hash;
 97     }
 98     // If atomic operation failed, we must inflate the header
 99     // into heavy weight monitor. We could add more code here
100     // for fast path, but it does not worth the complexity.
101   } else if (mark->has_monitor()) {
102     monitor = mark->monitor();
103     temp = monitor->header();
104     assert (temp->is_neutral(), "invariant") ;
105     hash = temp->hash();
106     if (hash) {
107       return hash;
108     }
109     // Skip to the following code to reduce code size
110   } else if (Self->is_lock_owned((address)mark->locker())) {
111     temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
112     assert (temp->is_neutral(), "invariant") ;
113     hash = temp->hash();              // by current thread, check if the displaced
114     if (hash) {                       // header contains hash code
115       return hash;
116     }
117     // WARNING:
118     //   The displaced header is strictly immutable.
119     // It can NOT be changed in ANY cases. So we have
120     // to inflate the header into heavyweight monitor
121     // even the current thread owns the lock. The reason
122     // is the BasicLock (stack slot) will be asynchronously
123     // read by other threads during the inflate() function.
124     // Any change to stack may not propagate to other threads
125     // correctly.
126   }
View Code

  该方法一般会被子类重写,String方法的hashCode方法代码 片段5

  计算方法是 s[0]31^(n-1) + s[1]31^(n-2) + … + s[n-1],其中s[0]表示字符串的第一个字符,n表示字符串长度;

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

  5、equals():返回 2个对象的内存地址是否相等

  源码 片段6

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

  该方法一般会被子类重写,String方法的equal方法代码 片段7

   先比较String对象内存地址相同,若相同则返回true,否则判断String对象对应字符的内容是否相等,若相等则返回true

 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() throws CloneNotSupportedException:返回复制对象

    先看下方法的说明:Note that all arrays are considered to implement the interface Cloneable and that the return type of the clone method of an array     type T[] is T[] where T is any reference or primitive type

    一起看下native方法 位于openjdk\\hotspot\\src\\share\\vm\\prims\\jvm.cpp中 JVM_Clone的实现  片段8

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方法执行效率高 ,看示例  片段9

 1 package jdk;
 2 
 3 import java.util.Calendar;
 4 import java.util.Date;
 5 
 6 public class ObjectCloneTest1 {
 7 
 8     static final int N = 100000;
 9 
10     public static void main(String[] args) {
11 
12         final Date date = new Date();
13 
14         {
15 
16             final long startTime = System.currentTimeMillis();
17             for (int i = 0; i < N; i++) {
18                 Date date2 = (Date) date.clone();
19             }
20 
21             final long endTime = System.currentTimeMillis();
22 
23             System.out.println("clone:" + (endTime - startTime) + "ms");
24         }
25 
26         {
27             final long startTime = System.currentTimeMillis();
28             for (int i = 0; i < N; i++) {
29                 final Calendar cal = Calendar.getInstance();
30                 cal.setTime(date);
31                 final Date date2 = cal.getTime();
32             }
33 
34             final long endTime = System.currentTimeMillis();
35             System.out.println("Calender.setTime:" + (endTime - startTime) + "ms");
36 
37         }
38 
39     }
40 
41 }

  2、clone生成的新对象与原对象的关系,需要区别2个对象建是否存在相同的引用或对应的内存地址是否存在共用情况,若存在则 该次clone为 “浅复制”,否则为“深复制”, 而且Object的clone方法是属于 “浅复制”,看示例  片段10

 1 package jdk;
 2 
 3 
 4 public class ObjectCloneTest2 {
 5 
 6     public static void main(String[] args) {
 7         Animal a1 = new Animal(1, "pig");
 8         Animal a2 = (Animal) a1.clone();
 9         System.out.println(a1.getName() == a2.getName() ? "浅复制" : "深复制");
10         
11         System.out.println(a1);
12         a1.setAge(11);
13         a1.setName("big pig");
14         System.out.println(a1.age + ":" + a1.name);
15         
16         System.out.println(a2);
17         System.out.println(a2.age + ":" + a2.name);
18         
19     }
20 
21 }
22 
23 class Animal implements Cloneable{
24     int age;
25     String name;
26 
27     Animal(int age, String name) {
28         this.age = age;
29         this.name = name;
30     }
31 
32     public Animal clone() {
33         Animal o = null;
34 
35         try {
36             o = (Animal) super.clone();
37         } catch (CloneNotSupportedException e) {
38             e.printStackTrace();
39         }
40 
41         return o;
42     }
43 
44     public int getAge() {
45         return age;
46     }
47 
48     public void setAge(int age) {
49         this.age = age;
50     }
51 
52     public String getName() {
53         return name;
54     }
55 
56     public void setName(String name) {
57         this.name = name;
58     }
59 }
View Code

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