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 }
该方法一般会被子类重写,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 }
"深复制"时,需要将共同关联的引用也复制完全看示例 片段11
以上是关于java基础之jdk源码Object的主要内容,如果未能解决你的问题,请参考以下文章