赞
踩
1.基本类型之间的拷贝如:
int apples = 5;
int pears = apples;
不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double,long)同样适用于该类情况,其实就是赋值。但是如果你复制的是一个对象,情况就有些复杂了。
2.异常现象:
创建一个类:
@Data
public class GoodStudent{
private String classNum;
}
创建一个测试类:
@Test public void test01() { GoodStudent goodStudent1 = new GoodStudent(); GoodStudent goodStudent2 = goodStudent1; /** * 输出结果: * GoodStudent(classNum=11) * GoodStudent(classNum=11) * 原因是: * 上面是将new GoodStudent()对象的引用给了goodStudent2, * 然后改了goodStudent2,goodStudent1也就跟着一起变 */ goodStudent2.setClassNum("11"); System.out.println(goodStudent1); System.out.println(goodStudent2); }
测试结果:
GoodStudent(classNum=11)
GoodStudent(classNum=11)
为什么改动了goodStudent2 ,而goodStudent1也跟着一起改动呢,原来是
GoodStudent goodStudent2 = goodStudent1;
只是将goodStudent1引用的对象赋给了goodStudent2,复制的只是对象引用,所有改动goodStudent2,本会就是改动了引用的对象,所以goodStudent1也会改变!
goodStudent1和goodStudent2 指向内存堆中同一个对象
那么如果不想让goodStudent1 也改变应该怎样做呢?这就要了解对象的拷贝了:
3.浅拷贝:
那么,怎样才能达到复制一个对象呢?
是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。
该方法的签名是:
protected native Object clone() throws CloneNotSupportedException;
因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。
要想对一个对象进行复制,就需要对clone方法覆盖。
步骤:
1.新建一个实体类,里面重写了clone() 方法,必须要实现Cloneable接口
@Data
public class GoodStudent implements Cloneable {
private String classNum;
public Object clone() {
GoodStudent stu = null;
try{
stu = (GoodStudent)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
2.新建测试类:
@Test
public void test02() throws CloneNotSupportedException {
GoodStudent stu1 = new GoodStudent();
stu1.setClassNum("1");
/**
* 这是浅拷贝 调用的是GoodStudent里面对clone方法的重写
*/
GoodStudent stu2 = (GoodStudent)stu1.clone();
System.out.println("好学生1:" + stu1.getClassNum());
System.out.println("好学生2:" + stu2.getClassNum());
stu2.setClassNum("2");
System.out.println("好学生1:" + stu1.getClassNum());
System.out.println("好学生2:" + stu2.getClassNum());
}
输出结果如下:
好学生1:1
好学生2:1
好学生1:1
好学生2:2
这样就实现了 对 对象的浅拷贝。问题又来了,如果GoodStudent中又有一个对象引用 比如 private Address address,如下代码所示,如果继续使用上面的复制方法,使类实现Cloneable接口,重写protected修饰的clone() 方法,但是里面的Address对象没有实现Cloneable接口,复制的时候,也只是复制的是对象的引用,难道让Address也要实现Cloneable接口吗,如果里面有十个八个对象呢,难道每个都需要吗,如果引用的是第三方的对象又该如何呢?
@Data public class GoodStudent implements Cloneable { private Address address; private String classNum; public Object clone() { GoodStudent stu = null; try{ stu = (GoodStudent)super.clone(); }catch(CloneNotSupportedException e) { e.printStackTrace(); } return stu; } }
如果进行上面的操作就是浅拷贝,那如何进行深拷贝呢?
4.深拷贝:
新建一个类:
@Data
public class Dog implements Serializable {
private String dogName;
}
再建一个类并引用Dog对象:
@Data
public class Animal implements Serializable {
private String name;
private Dog dog;
}
这两个类都实现Serializable接口:(必须要实现)
再建一个实现深拷贝的接口实现类:
public class ObjCloner { @SuppressWarnings("unchecked") public static <T>T cloneObj(T obj){ T retVal = null; try{ // 将对象写入流中 ByteArrayOutputStream ins = new ByteArrayOutputStream(); ObjectOutputStream inos = new ObjectOutputStream(ins); inos.writeObject(obj); // 从流中读出对象 ByteArrayInputStream outs = new ByteArrayInputStream(ins.toByteArray()); ObjectInputStream ois = new ObjectInputStream(outs); retVal = (T)ois.readObject(); }catch(Exception e){ e.printStackTrace(); } return retVal; } }
测试类:
@Test public void test03(){ Animal animal = new Animal(); animal.setName("大象"); Dog dog = new Dog(); dog.setDogName("小狗"); animal.setDog(dog); Animal animal1 = ObjCloner.cloneObj(animal); System.out.println("动物的名称:"+animal.getName()+" 狗的名称:" + animal.getDog().getDogName()); System.out.println("克隆后动物名称:"+animal1.getName()+" 克隆后狗的名称:" + animal1.getDog().getDogName()); System.out.println(" ----------------------------------------------------------"); animal1.setName("狮子"); animal1.getDog().setDogName("小狗狗"); System.out.println("动物的名称:"+animal.getName()+" 狗的名称:" + animal.getDog().getDogName()); System.out.println("克隆后动物名称:"+animal1.getName()+" 克隆后狗的名称:" + animal1.getDog().getDogName()); }
打印结果如下:
动物的名称:大象 狗的名称:小狗
克隆后动物名称:大象 克隆后狗的名称:小狗
---------------------------------------------------------------------------------------
动物的名称:大象 狗的名称:小狗
克隆后动物名称:狮子 克隆后狗的名称:小狗狗
这就实现了,Java对象的复制,也就是深浅拷贝
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。