1. 前言
今天学习了java实现拷贝的四种方式,这里记录一下。
2. 正文
Java实现对象克隆的四种方法
(1)将A对象的值分别通过set方法加入B对象中;
(2)通过重写java.lang.Object类中的方法clone();
(3)通过org.apache.commons中的工具类BeanUtils进行对象复制;
(4)通过序列化实现对象的复制。
2.1 将A对象的值分别通过set方法加入B对象中
如果属性少的话就这样可以达到目的,可是一旦修改了Student类,每一处克隆都要额外添加set get方法,将非常繁琐
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = new Student();
stu2.setNumber(stu1.getNumber());
2.2 重写java.lang.Object类中的方法clone()
浅克隆(ShallowClone)
1、 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常)
2、 覆盖clone()方法,访问修饰符设为public。直接调用父类的clone方法
class Student implements Cloneable{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
// 测试:public class Main {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setNumber(1529786);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
stu2.setNumber(1571707);
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
}
}
在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
class Address {
private String add;
public String getAdd() {
return add;
}
public void setAdd(String add) {
this.add = add;
}
}
class Student implements Cloneable{
private int number;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone(); //浅复制
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
public class Test {
public static void main(String args[]) {
Address addr = new Address();
addr.setAdd("成都市");
Student stu1 = new Student();
stu1.setNumber(123);
stu1.setAddr(addr);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
addr.setAdd("犀浦区");
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
}
}
深克隆(DeepClone)
class Address implements Cloneable {
private String add;
public String getAdd() {
return add;
}
public void setAdd(String add) {
this.add = add;
}
@Override
public Object clone() {
Address addr = null;
try{
addr = (Address)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return addr;
}
}
class Student implements Cloneable{
private int number;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone(); //浅复制
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
stu.addr = (Address)addr.clone(); //深度复制
return stu;
}
}
public class Test {
public static void main(String args[]) {
Address addr = new Address();
addr.setAdd("杭州市");
Student stu1 = new Student();
stu1.setNumber(123);
stu1.setAddr(addr);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
addr.setAdd("西湖区");
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
}
}
对Student类clone方法,stu = (Student)super.clone(); 进行浅复制,然后对属性addr再进行克隆,直到所有引用类型都覆盖到
测试:
2.3 工具类BeanUtils进行对象复制
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = new Student();
BeanUtils.copyProperties(stu2,stu1);
一行代码搞定,简单粗暴,YEAH!(*^-^*)
2.4 通过序列化实现对象的复制
public class Demo2 implements Serializable {
private String name;
private String value;
private DemoInternal2 demoInternal2;
/*省略getter和setter方法*/
// 深度复制
public Demo2 myclone() {
Demo2 demo2 = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
demo2 = (Demo2) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return demo2;
}
}