JavaSE---Object-clone()
一、概述
/**
* <what>
* 创建并返回此对象的一个副本;
* (按照原对象,创建一个新的对象[复制原对象的内容])
*/
二、已经存在new或反射等技术,为啥还需要Object的clone方法?
1、new关键字、反射创建对象的弊端
/**
* 1、new关键字、反射创建对象的弊端
* 通过new、反射可以创建内容一样的对象;
* 但是,创建对象之后,需要通过setter为新对象设置属性值,如果需要创建更多内容一样的对象,setter方法将不断重复;
*
* 解决:
* 使用Object的clone方法;
*/
public class User{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
private static void newTest() {
User user = new User();
user.setName("rose");
User userCopy = new User();
userCopy.setName(user.getName());
System.out.println(user);
System.out.println(userCopy);
}
private static void reflectTest() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
User user = new User();
user.setName("rose");
Class<?> userClazz = Class.forName("com.an.object.User");
User userCopy = (User) userClazz.newInstance();
userCopy.setName(user.getName());
System.out.println(user);
System.out.println(userCopy);
}
2、使用Object的clone方法
/**
* 1、需要调用clone方法的对象实现java.lang.Cloneable接口
* 2、重新clone方法
*/
public class User implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
private static void cloneTest() throws CloneNotSupportedException {
User user = new User();
user.setName("rose");
User userCopy = user.clone();
System.out.println(user);
System.out.println(userCopy);
}
三、浅拷贝
/**
* <浅拷贝>
* what
* clone对象 是一个新对象
* clone对象的成员变量 与 原对象的成员变量 是同一个数据;
*
* 缺点
* 由于 原对象与clone对象 的成员变量 是同一个数据,任意一个对象对成员变量进行修改,原对象与clone对象的成员变量都会被修改;
*/
public class User implements Cloneable{
private String name;
private Man man;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", man=" + man +
'}';
}
public static class Man{
private String job;
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Man{" +
"job='" + job + '\'' +
'}';
}
}
}
private static void shallowClone() throws CloneNotSupportedException {
User user = new User();
user.setName("rose");
User.Man man = new User.Man();
man.setJob("teacher");
user.setMan(man);
User userCopy = user.clone();
System.out.println(user.getMan().hashCode()); // 1872034366
System.out.println(userCopy.getMan().hashCode()); // 1872034366
user.getMan().setJob("coder");
System.out.println(user.getMan()); // Man{job='coder'}
System.out.println(userCopy.getMan()); // Man{job='coder'}
}
四、深拷贝
1、使用java.lang.Cloneable接口深拷贝
/**
* <深拷贝>
* what
* clone对象是一个新对象
* clone对象的成员变量 也是一个新对象;
*
* 步骤
* 1、原对象、原对象的成员变量 实现java.lang.Cloneable接口,重写clone方法
* 2、原对象的clone方法调用成员变量的clone方法;
*
* 使用java.lang.Cloneable接口实现深拷贝的弊端:
* 成员变量重复实现java.lang.Cloneable接口
* 成员变量重复实现clone方法
* 原对象的clone方法重复改写
*
* 解决
* 使用IO流的方式进行 深拷贝
* (解决重复修改源代码的问题)
*
*/
public class User implements Cloneable{
private String name;
private Man man;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
@Override
public User clone() throws CloneNotSupportedException {
User clone = (User) super.clone();
clone.setMan(man.clone());
return clone;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", man=" + man +
'}';
}
public static class Man implements Cloneable{
private String job;
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public Man clone() throws CloneNotSupportedException {
return (Man) super.clone();
}
@Override
public String toString() {
return "Man{" +
"job='" + job + '\'' +
'}';
}
}
}
private static void deepClone() throws CloneNotSupportedException {
User user = new User();
user.setName("rose");
User.Man man = new User.Man();
man.setJob("teacher");
user.setMan(man);
User userCopy = user.clone();
System.out.println(user.getMan().hashCode()); // 1872034366
System.out.println(userCopy.getMan().hashCode()); // 1581781576
user.getMan().setJob("coder");
System.out.println(user.getMan()); // Man{job='coder'}
System.out.println(userCopy.getMan()); // Man{job='teacher'}
}
2、使用IO流深拷贝
/**
* <深拷贝-使用IO流>
* API
* ByteArrayOutputStream
* ByteArrayInputStream
* ObjectOutputStream
* ObjectInputStream
* 步骤
* 1、创建ByteArrayOutputStream,将数据转换为字节
* 2、创建ObjectOutputStream,关联ByteArrayOutputStream
* 3、使用ObjectOutputStream的writeObject,读取要复制的对象
* 4、使用ByteArrayInputStream读取ByteArrayOutputStream转换的对象字节数据
* 5、创建ObjectInputStream读取对象字节数据,创建新的对象
*
* 原对象及其变量需要实现java.io.Serializable接口
*/
package com.an.object;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author apy
* @description
* @date 2022/4/24 17:22
*/
public class User implements Serializable{
private String name;
private Man man;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
public User copy(){
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
User user = (User) objectInputStream.readObject();
return user;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", man=" + man +
'}';
}
public static class Man implements Serializable {
private String job;
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Man{" +
"job='" + job + '\'' +
'}';
}
}
}
private static void ioDeepClone() {
User user = new User();
user.setName("rose");
User.Man man = new User.Man();
man.setJob("teacher");
user.setMan(man);
User userCopy = user.copy();
System.out.println(user.hashCode()); // 225534817
System.out.println(userCopy.hashCode()); // 122883338
System.out.println(user.getMan().hashCode()); // 1878246837
System.out.println(userCopy.getMan().hashCode()); // 666641942
user.getMan().setJob("coder");
System.out.println(user.getMan()); // Man{job='coder'}
System.out.println(userCopy.getMan()); // Man{job='teacher'}
}
五、为什么使用clone方法需要实现java.lang.Cloneable接口
/**
* <为什么使用clone方法需要实现java.lang.Cloneable接口>
* 下载JDK源码,进入hotspot/src/share/vm/prims/jvm.cpp文件中
*
* // 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());
* }
*
* Check if class of obj supports the Cloneable interface.检查指定的class是否实现java.lang.Cloneable接口(数组默认支持clone);
* 如果 !klass->is_cloneable() 抛出CloneNotSupportedException;
*
* 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;
*/
浙公网安备 33010602011771号