Java实例 Part6:Java中的克隆
程序员文章站
2023-02-09 22:18:00
Part6:Java中的克隆 @[toc] Example01:Java对象的假克隆 对象的克隆是Java中的一项高级技术,获得与其相同的对象。 基本数据类型可以使用“=”来进行克隆,此时两个变量除了相等是没有任何关系的。而对于引用类型数据不能简单地使用“=”进行克隆,这与J ......
目录
part6:java中的克隆
@
***
example01:java对象的假克隆
- 对象的克隆是java中的一项高级技术,获得与其相同的对象。
基本数据类型可以使用“=”来进行克隆,此时两个变量除了相等是没有任何关系的。而对于引用类型数据不能简单地使用“=”进行克隆,这与java的内存空间使用有关。
java将内存空间分成两块,即栈和堆。在栈中保存基本类型和引用变量;在堆中保存对象。对于引用变量而言,使用“=”将修改引用,而不是复制堆中的对象。此时两个引用变量将指向同一个对象。因此,如果一个变量对其修改则会改变另一个变量。
运行结果:
代码实现:
public class employee { private string name; private int age; //省略set()和get()方法 @override public string tostring() { return "employee{" + "name='" + name + '\'' + ", age=" + age + '}'; } public static void main(string[] args) { system.out.println("-----克隆之前:--------"); employee employee1 = new employee(); employee1.setname("hyn"); employee1.setage(20); system.out.println("员工1的信息:\n"+employee1); system.out.println("-----克隆之后:--------"); employee employee2 = employee1; //将employee1赋值给employee2 employee2.setname("azw"); employee2.setage(21); system.out.println("员工1的信息:\n"+employee1); system.out.println("员工2的信息:\n"+employee2); } }
example02:java对象的浅克隆
在克隆对象时,如果对象的成员变量是基本数据类型,则使用浅克隆即可完成。如果对象的成员变量包括可变引用类型,则需要深克隆。
运行结果:
代码实现:
//address.java public class address { private string state; //所在国家 private string province; //所在省 private string city; //所在城市 public address(string state, string province, string city) { this.state = state; this.province = province; this.city = city; } //省略set()和get()方法 @override public string tostring() { stringbuilder sb = new stringbuilder(); sb.append("国家:"+state+","); sb.append("省:"+province+","); sb.append("市:"+city); return sb.tostring(); } } //employee.java public class employee implements cloneable{ private string name; private int age; private address address; public employee(string name, int age, address address) { this.name = name; this.age = age; this.address = address; } //省略set()和get()方法 @override public string tostring() { stringbuilder sb = new stringbuilder(); sb.append("姓名:"+name+","); sb.append("年龄:"+age+","); sb.append("\n地址:"+address); return sb.tostring(); } @override public employee clone() throws clonenotsupportedexception { //实现浅克隆 employee employee = (employee) super.clone(); return employee; } }
测试代码:
class test { public static void main(string[] args) throws clonenotsupportedexception { system.out.println("*****克隆之前:******"); address address = new address("中国", "湖北", "武汉"); employee employee1 = new employee("azw", 20, address); system.out.println("员工1的信息:\n" + employee1); //employee1的信息 system.out.println("*****克隆之后:******"); employee employee2 = employee1.clone(); //使用克隆创建employee2 employee2.getaddress().setstate("中国"); //修改地址 employee2.getaddress().setprovince("黑龙江"); employee2.getaddress().setcity("哈尔滨"); employee2.setname("hyn"); employee2.setage(21); system.out.println("员工1的信息:\n" + employee1); system.out.println("员工2的信息:\n" + employee2); } }
- 如果引用类型是不可变的,如string类对象,则不必进行深克隆。
***
example03:java对象的深克隆
- 如果类的成员变量中包括可变引用类型,则需进行深克隆。
运行结果:
代码实现:
//address.java public class address implements cloneable{ private string state; //所在国家 private string province; //所在省 private string city; //所在城市 public address(string state, string province, string city) { this.state = state; this.province = province; this.city = city; } //省略set()和get()方法 @override public string tostring() { stringbuilder sb = new stringbuilder(); sb.append("国家:"+state+","); sb.append("省:"+province+","); sb.append("市:"+city); return sb.tostring(); } //--------------------------- @override public address clone() throws clonenotsupportedexception { //address类中的域不是基本类型就是不可变类型,所以可以直接使用浅克隆 address address = (address) super.clone(); return address; } //--------------------------- } //employee.java public class employee implements cloneable{ private string name; private int age; private address address; public employee(string name, int age, address address) { this.name = name; this.age = age; this.address = address; } //省略set()和get()方法 @override public string tostring() { stringbuilder sb = new stringbuilder(); sb.append("姓名:"+name+","); sb.append("年龄:"+age+","); sb.append("\n地址:"+address); return sb.tostring(); } @override public employee clone() throws clonenotsupportedexception { //实现深克隆 employee employee = (employee) super.clone(); //--------------------------------- employee.address = address.clone(); //--------------------------------- return employee; } } //测试代码同example02测试代码.
-
要点:通常情况下,需要用到克隆对象时都需要使用深克隆。
***
example04:序列化与对象克隆
如果类的成员变量比较复杂,例如使用了多个可变的引用类型,使用clone()方法是非常麻烦的,所以可以考虑序列化的方式完成克隆。
运行结果:
代码实现:
import java.io.serializable; public class employee implements serializable { //同example04中employee.java的代码 } public class address implements serializable { //同example04中assress.java的代码 }
测试代码:
class test { public static void main(string[] args) throws ioexception, classnotfoundexception { system.out.println("*****序列化之前:******"); address address = new address("中国", "湖北", "武汉"); employee employee1 = new employee("azw", 20, address); system.out.println("员工1的信息:\n" + employee1); //employee1的信息 system.out.println("*****序列化之后:******"); employee employee2 = null; objectoutputstream out = new objectoutputstream(new fileoutputstream("e:\\employee.txt")); out.writeobject(employee1); //将对象写入到本地文件中 objectinputstream in = new objectinputstream(new fileinputstream("e:\\employee.txt")); employee2 = (employee)in.readobject(); //从本地文件中读取对象 if (employee2 != null) { employee2.getaddress().setstate("中国"); //修改地址 employee2.getaddress().setprovince("黑龙江"); employee2.getaddress().setcity("哈尔滨"); employee2.setname("hyn"); employee2.setage(21); system.out.println("员工1的信息:\n" + employee1); system.out.println("员工2的信息:\n" + employee2); } } }
要点:进行序列化的类需要实现serializable接口,该接口中并没有定义任何方法,是一个标识接口。如果类中有可变的引用类型成员变量,则该变量需要实现serializable接口。本实例采用将对象写入本地文件的方式完成序列化。
***
example05:深克隆和序列化的效率比较
- 通过使用这两种方式克隆100000个对象,并输出花费的时间来比较这两种方法的效率。
运行结果:
代码实现:
import java.io.serializable; public class employee implements cloneable,serializable { private string name; private int age; public employee(string name, int age) { this.name = name; this.age = age; } @override public string tostring() { stringbuilder sb = new stringbuilder(); sb.append("姓名:"+name+","); sb.append("年龄:"+age+","); return sb.tostring(); } @override public employee clone() throws clonenotsupportedexception { //使用父类的clone()方法实现深克隆 employee employee = (employee) super.clone(); return employee; } } 测试代码: import java.io.*; import java.util.arraylist; import java.util.list; class test { public static void main(string[] args) throws ioexception, classnotfoundexception, clonenotsupportedexception { list<employee> employees = new arraylist<employee>(); //创建列表保存对象 employee employee = new employee("azw", 20); //创建对象 long currenttime = system.currenttimemillis(); //获得当前系统时间 //使用克隆方式获得对象 for (int i = 0;i<100000;i++){ employees.add(employee.clone()); } system.out.println("克隆花费的时间:"+(system.currenttimemillis()-currenttime)+"毫秒"); currenttime = system.currenttimemillis(); //获得当前系统时间 for (int i = 0;i<100000;i++){ bytearrayoutputstream bout = new bytearrayoutputstream(); //创建字节数组输出流 objectoutputstream out = new objectoutputstream(bout); //创建对象输出流 out.writeobject(employee); //将对象写入到输出流中 //获得字节输出流内容 bytearrayinputstream bin = new bytearrayinputstream(bout.tobytearray()); objectinputstream in = new objectinputstream(bin); //创建对象输入流 employees.add((employee) in.readobject()); //读取对象 } system.out.println("序列化花费的时间:"+(system.currenttimemillis()-currenttime)+"毫秒"); } }
要点:使用bytearrayoutputstream和bytearrayinputstream可以将对象保存在内存中,这样就不必产生一个本地文件来完成序列化的功能。
***
假克隆、浅克隆和深克隆的应用范围
假克隆 | 基本数据类型 |
---|---|
浅克隆 | 基本数据类型、不可变引用类型 |
深克隆 | 可变引用类型 |
上一篇: 如何健脾补气 推荐4款药膳粥
下一篇: 最浪漫的情诗