本文出自:http://blog.csdn.net/dt235201314/article/details/78318399
一丶概述
JAVA中所有的类都继承自Object类,就从Object作为源码解析的开始。
二丶常见方法
![](https://img.haomeiwen.com/i5260759/cd3cff2e030d1bbd.png)
注: 以上绿色方法为 非native方法 粉色方法为 native方法)
什么是native方法?
native关键字标识的java方法为本地方法,底层是有c/c++编写的程序编译后dll文件,java加载dll文件后,可用通过本地方法调用dll中函数,如有疑问可用参考JNI使用方式。
什么是JNI方法?
向东是底层,向西是应用,咱们先一路向西。向东参考:JNI方法使用
1.Object():默认构造函数(源码无系统默认提供)
2.void registerNatives()
/* 一个本地方法,具体是用C(C++)在DLL中实现的,然后通过JNI调用。*/
private static native void registerNatives();
/* 对象初始化时自动调用此方法*/
static {
registerNatives();
}
3.final getClass()
/* 返回此 Object 的运行时类。*/
public final native Class<?> getClass();
例:
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()方法
/*
hashCode 的常规协定是:
1.在应用程序执行期间,如果一个对象用于equals()方法的属性没有被修改的话,
那么要保证对该对象多次返回的hashcode值要相等。
2.如果2个对象通过equals()方法判断的结果为true,那么要保证二者的hashcode值相等。
3.如果2个对象通过equals()方法判断的结果为false,那么对二者hashcode值是否相等并没有明确要求。
如果不相等,那么能够提升散列表的性能。
*/
public native int hashCode();
实际计算方法:
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)
public boolean equals(Object obj) {
return (this == obj);
}
从这里我们可以看到,equals(obj)方法最根本的实现就是‘==’,因此对于一些自定义类,如果没有重写hashcode()方法和equals()方法的话,利用‘==’和equals()方法比较的结果是一样的。对于‘==’比较的是地址,equals()方法比较的是内容这种说法,是片面的。(虽然在最常用的String类中是这样的)。
equal方法常被重写
例:String(先比较String对象内存地址相同,若相同则返回true,否则判断String对象对应字符的内容是否相等,若相等则返回true)
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()
/*本地CLONE方法,用于对象的复制。*/
protected native Object clone() throws CloneNotSupportedException;
一起看下native方法 位于openjdk\hotspot\src\share\vm\prims\jvm.cpp中 JVM_Clone的实现 片段
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方法执行效率高 ,看示例
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");
}
}
}
![](https://img.haomeiwen.com/i5260759/3791e8f7b062dc15.png)
2、clone生成的新对象与原对象的关系,需要区别2个对象建是否存在相同的引用或对应的内存地址是否存在共用情况,若存在则 该次clone为 “浅复制”,否则为“深复制”, 而且Object的clone方法是属于 “浅复制”,看示例
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;
}
}
![](https://img.haomeiwen.com/i5260759/b9fcebfb70bea133.png)
"深复制"时,需要将共同关联的引用也复制完全看示例
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()
/*返回该对象的字符串表示。非常重要的方法*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
默认返回对象的名称及引用地址,但一般被子类重写用于说明子类相关属性值描述
8.final notify()
/*不能被重写,唤醒在此对象监视器上等待的单个线程。*/
public final native void notify();
9.final notifyAll()
/*唤醒在此对象监视器上等待的所有线程。*/
public final native void notifyAll();
10.final void wait()方法
/*在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。
当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。*/
public final void wait() throws InterruptedException {
wait(0);
}
11.final native void wait(long timeout)
/*在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。*/
public final native void wait(long timeout) throws InterruptedException;
该方法使当前线程等待,直到另外一个线程调用该对象的notify或notifyAll方法,或者等待时间已到,当前线程才会从等待池移到运行池。
如果在wait之前或者wait的时候,当前线程被中断了,那么直到该线程被恢复的时候才会抛出中断异常(InterruptedException)
12.final void wait(long timeout,int nanos)
/* 在其他线程调用此对象的 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()
/*当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。*/
protected void finalize() throws Throwable { }
垃圾回收器在认为该对象是垃圾对象的时候会调用该方法。子类可以通过重写该方法来达到资源释放的目的。
在方法调用过程中出现的异常会被忽略且方法调用会被终止。
任何对象的该方法只会被调用一次。
三丶参看文章
Object类源码解析
【java基础之jdk源码】Object
四丶相关面试题
网友评论