1、区别
2、浅拷贝
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
1、 基本类型
如果变量是基本很类型,则拷贝其值,比如int、float等。
2、 对象
如果变量是一个实例对象,则拷贝其地址引用,也就是说此时新对象与原来对象是公用该实例变量。
3、 String字符串
若变量为String字符串,则拷贝其地址引用。但是在修改时,它会从字符串池中重新生成一个新的字符串,原有字符串对象保持不变。
如何使用clone()方法
I. 实现Cloneable 接口
II. 覆盖clone()
III. 在自己的clone()中调用super.clone()
IV. 在自己的clone()中捕获异常
//浅拷贝实现,默认的拷贝是浅拷贝
package cn.cupcat.java8;
public class Person implements Cloneable{
private String name;
private int age;
private int[] ints;
public int[] getInts() {
return ints;
}
public Person(String name, int age, int[] ints) {
this.name = name;
this.age = age;
this.ints = ints;
}
public void setInts(int[] ints) {
this.ints = ints;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 默认实现
* */
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
3、深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
//深拷贝的实现,通过序列化实现深拷贝
public static <T extends Serializable> T clone(T obj){
T cloneObj = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
//使用该工具类的对象必须要实现Serializable接口,否则是没有办法实现克隆的。
public class Person implements Serializable{
private static final long serialVersionUID = 2631590509760908280L;
..................
//去除clone()方法
}
public class Email implements Serializable{
private static final long serialVersionUID = 1267293988171991494L;
...................
}
//CloneTest3 序列化深拷贝
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class CloneTest3
{
public static void main(String[] args) throws Exception
{
Teacher3 t = new Teacher3();
t.setName("Teacher Wang");
t.setAge(50);
Student3 s1 = new Student3();
s1.setAge(20);
s1.setName("ZhangSan");
s1.setTeacher(t);
Student3 s2 = (Student3) s1.deepClone();
System.out.println("拷贝得到的信息:");
System.out.println(s2.getName());
System.out.println(s2.getAge());
System.out.println(s2.getTeacher().getName());
System.out.println(s2.getTeacher().getAge());
System.out.println("---------------------------");
// 将复制后的对象的老师信息修改一下:
s2.getTeacher().setName("New Teacher Wang");
s2.getTeacher().setAge(28);
System.out.println("修改了拷贝对象的教师后:");
System.out.println("拷贝对象的教师:");
System.out.println(s2.getTeacher().getName());
System.out.println(s2.getTeacher().getAge());
System.out.println("原来对象的教师:");
System.out.println(s1.getTeacher().getName());
System.out.println(s1.getTeacher().getAge());
// 由此证明序列化的方式实现了对象的深拷贝
}
}
class Teacher3 implements Serializable
{
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
class Student3 implements Serializable
{
private String name;
private int age;
private Teacher3 teacher;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public Teacher3 getTeacher()
{
return teacher;
}
public void setTeacher(Teacher3 teacher)
{
this.teacher = teacher;
}
public Object deepClone() throws Exception
{
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}