Java内容的复制三种方法转载
原创1、概述
在实际的编程过程中,我们经常会遇到这样的情况:有一个对象A,在某个时刻A一些有效的值已经包含在 需要一笔钱A完全相同的新物体B此后,在B任何更改都不会影响A价值在于,也就是,A与B是两个独立的物体,B的初始值A确定了对象。例如,以下过程显示了这种情况:
class Student {
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public class Test {
public static void main(String args[]) {
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = stu1;
stu1.setNumber(54321);
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
}
}
结果:
学生1:54321
学生2:54321
为什么要换学生?2学生号,学生1学号也变了吗?
原因出在(stu2 = stu1) 这句话。这一声明的目的是stu1将引用分配给。stu2,
这样,stu1和stu2指向内存堆中的同一对象。图:
那么,如何才能制作一个干净的对象副本呢?在……里面 Java在语言中,这一需求不能通过简单的赋值语句来满足。有很多方法可以满足这种需求,
(1)将A对象的值分别传递。set方法加入B对象中;
(2)通过重写java.lang.Object类中的方法clone();
(3)通过org.apache.commons中的工具类BeanUtils和PropertyUtils对象复制;
(4对象的复制是通过序列化实现的。
2、将A对象的值分别传递。set方法加入B对象中
为了逐个赋值,为了演示简单性,此示例设置了一个属性:
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = new Student();
stu2.setNumber(stu1.getNumber());
我们发现,属性逐个赋值非常方便,但当属性较多时,需要始终get、set这很麻烦。
3、重写java.lang.Object类中的方法clone()
首先,介绍了两种不同的克隆方法,浅层克隆(ShallowClone)和深克隆(DeepClone)。
在Java在语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括。int、double、byte、boolean、char简单数据类型,如类、接口、数组和其他复杂类型。浅克隆和深克隆的主要区别在于是否支持复制引用类型的成员变量,下面将对两者进行详细描述。
3.1 浅克隆
一般步骤:
需要实现复制的类。Clonenable接口(如果未实现,则调用clone方法将引发CloneNotSupportedException异常), 该接口是标记接口。(不包含任何方法)
覆盖clone()方法,则设置访问修饰符。public。方法调用super.clone()方法获取所需的复制对象。(native对于本地方法)
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 Test {
public static void main(String args[]) {
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
stu2.setNumber(54321);
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
}
}
结果:
学生1:12345
学生2:12345
学生1:12345
学生2:54321
在浅层克隆中,如果Prototype对象的成员变量是值类型,则会复制到克隆对象;如果Prototype对象的成员变量是引用类型,则会将被引用对象的地址复制到克隆对象,即Prototype对象和克隆对象的成员变量指向相同的内存地址。
简单地说,在浅克隆中,当复制对象时,只复制其自身的成员变量和其中包含的值类型,而不复制引用类型的成员对象。
在Java语言,通过覆盖Object类的clone()方法可以实现浅层克隆。
3.2 深克隆
package abc;
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());
}
}
结果:
学生1:123,地址:杭州市
学生2:123,地址:杭州市
学生1:123,地址:西湖区
学生2:123,地址:西湖区
为什么两个学生的地址都变了?
原因是浅层复制仅复制addr对变量的引用并不会真正打开另一块空间,即复制值并返回对新对象的引用。
以实现对象的真实副本,而不是纯粹的参考副本。我们需要Address类可以复制和修改。clone方法,完整的代码如下所示:
package abc;
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());
}
}
结果:
学生1:123,地址:杭州市
学生2:123,地址:杭州市
学生1:123,地址:西湖区
学生2:123,地址:杭州市
在深度克隆中,无论Prototype对象的成员变量是值类型还是引用类型,都会将副本复制到克隆对象,并且深度克隆还会将原型对象的所有引用对象复制到克隆对象。
简单地说,在深度克隆中,除了对象本身之外,对象中包含的所有成员变量都将被复制。
在Java语言,如果需要实现深度克隆,您可以重写Object类的clone()方法实现,也可以序列化。(Serialization)和其他方式来实现。
(如果引用类型也包含许多引用类型,或者内部引用类型的类包含引用类型,请使用它。clone这种方法会很麻烦。在这一点上,我们可以序列化对象的深度克隆。)
4、工具类BeanUtils和PropertyUtils进行对象复制
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = new Student();
BeanUtils.copyProperties(stu2,stu1);
这种编写方法,无论多少种属性,只需要一行代码,非常方便!除BeanUtils还有一个名字PropertyUtils的工具类,它还提供了copyProperties()方法、角色和BeanUtils同名的方法很相似,主要的区别是BeanUtils提供类型转换功能,即发现两个JavaBean如果同名属性的类型不同,则会在支持的数据类型范围内进行转换,而PropertyUtils不支持此功能,但速度会更快。在实际开发中,BeanUtils使用更普遍,犯错的风险也更低。
5,通过序列化复制对象。
序列化是将对象写入流的过程,其中对象是原始对象的副本,而原始对象仍然存在于内存中。通过序列化实现的复制不仅可以复制对象本身,还可以复制它所引用的成员对象,因此可以通过将对象序列化为流并将其从流中读出来实现深度克隆。需要注意的是,必须实现可序列化的对象类。Serializable接口,否则无法实现序列化操作。
版权声明:本文是CSDN博主「chun_soft“原文,跟上。CC 4.0 by-sa版权协议,转载请附上原始来源链接和本声明。
原始链接:https://blog.csdn.net/ztchun/article/details/79110096
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除