欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java实例 Part6:Java中的克隆

程序员文章站 2023-02-09 22:18:00
Part6:Java中的克隆 @[toc] Example01:Java对象的假克隆 对象的克隆是Java中的一项高级技术,获得与其相同的对象。   基本数据类型可以使用“=”来进行克隆,此时两个变量除了相等是没有任何关系的。而对于引用类型数据不能简单地使用“=”进行克隆,这与J ......

目录

part6:java中的克隆


@
***

example01:java对象的假克隆

  • 对象的克隆是java中的一项高级技术,获得与其相同的对象。

  基本数据类型可以使用“=”来进行克隆,此时两个变量除了相等是没有任何关系的。而对于引用类型数据不能简单地使用“=”进行克隆,这与java的内存空间使用有关。   
  java将内存空间分成两块,即栈和堆。在栈中保存基本类型和引用变量;在堆中保存对象。对于引用变量而言,使用“=”将修改引用,而不是复制堆中的对象。此时两个引用变量将指向同一个对象。因此,如果一个变量对其修改则会改变另一个变量。

运行结果:
Java实例 Part6: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对象的浅克隆

  在克隆对象时,如果对象的成员变量是基本数据类型,则使用浅克隆即可完成。如果对象的成员变量包括可变引用类型,则需要深克隆。

运行结果:
Java实例 Part6: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对象的深克隆

  • 如果类的成员变量中包括可变引用类型,则需进行深克隆。

运行结果:
Java实例 Part6: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()方法是非常麻烦的,所以可以考虑序列化的方式完成克隆。
运行结果:
Java实例 Part6:Java中的克隆
代码实现:

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个对象,并输出花费的时间来比较这两种方法的效率。

运行结果:
Java实例 Part6:Java中的克隆
代码实现:

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可以将对象保存在内存中,这样就不必产生一个本地文件来完成序列化的功能。
***

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

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