java对象复制与克隆
Posted zhangjin1120
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java对象复制与克隆相关的知识,希望对你有一定的参考价值。
public class ObjectCopyTest {
public static class Person implements Cloneable{
int age;
String name;
static class Info {
public String address;
}
Info info;
@Override
protected Person clone() {
Person p = null;
try {
p = (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
public static void main(String[] args) {
Person p = new Person();
p.age=22;
p.name = "zhangsan";
p.info = new Person.Info();
p.info.address = "xxx";
Person p2 = p.clone();
System.out.println(p2.info.address);
System.out.println(p == p2);
}
}
-
Cloneable
接口内部没有抽象方法,Person
为什么要实现Cloneable
?查看
Cloneable
接口注释如下
翻译翻译:一个类实现指向
Object#clone()
方法的Cloneable
接口,说明该类的对象创建一个字段对字段的副本是合法的。调用Object’s clone方法,在未实现Cloneable
导致抛出异常CloneNotSupportedException
。按照约定,实现此接口的类应该用public
方法重写Object.clone()
(这个方法是protected
)。有关重写此方法的详细信息,请参见Object.clone()
。请注意,此接口不包含克隆方法。因此,不可能仅仅因为实现了这个接口就克隆一个对象。即使反射调用clone方法,也不能保证它会成功。
总结一下就是只有实现Cloneable
接口,并且重写clone
方法,才能实现对象克隆。
protected native Object clone() throws CloneNotSupportedException;
是一个native方法,源码看不到。这能阻挡我们探索真理吗?不存在的。穷追不舍,Object.c中,有如下几行:
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
看来,这个clone
方法,对应着一个叫JVM_Clone
的C函数。继续找,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
有没有发现
if (!klass->is_cloneable()) {
...
}
大致可以推断,这个Cloneable
接口确实是一个判断标志。
以上是关于java对象复制与克隆的主要内容,如果未能解决你的问题,请参考以下文章