博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java实例 Part6:Java中的克隆
阅读量:4481 次
发布时间:2019-06-08

本文共 8871 字,大约阅读时间需要 29 分钟。

目录

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.javapublic 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.javapublic 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
employees = new ArrayList
(); //创建列表保存对象 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可以将对象保存在内存中,这样就不必产生一个本地文件来完成序列化的功能。

***

假克隆、浅克隆和深克隆的应用范围

假克隆 基本数据类型
浅克隆 基本数据类型、不可变引用类型
深克隆 可变引用类型

转载于:https://www.cnblogs.com/hynazwaa/p/9906308.html

你可能感兴趣的文章
elasticsearch-head安装
查看>>
one R chart example
查看>>
汇编实验二
查看>>
HDU 3440 House Man
查看>>
大数据笔记(十二)——使用MRUnit进行单元测试
查看>>
Groovy 学习手册(5)
查看>>
PostgreSQL-Python数据库连接-psycopg
查看>>
Delphi下WebBrowser应用示例
查看>>
osg(OpenSceneGraph)学习笔记1:智能指针osg::ref_ptr<>
查看>>
MySQL中数据表的查操作
查看>>
【CODEFORCES】 C. Dreamoon and Strings
查看>>
la 3942 Rember_前缀树
查看>>
到底私钥和公钥哪个是用来加密 哪个是用来解密的
查看>>
TCP/IP协议详解
查看>>
LeetCode 26 Remove Duplicates from Sorted Array
查看>>
Java 输入/输出 反射
查看>>
href="#"与href="javascript:void(0)"的区别
查看>>
Ansible用于网络设备管理 part 3 使用NAPALM成品库
查看>>
抽象类和接口的区别以及jdk1.8之后接口里面可以实现方法
查看>>
shell命令之一天一见:awk
查看>>