美文网首页
Java☞克隆

Java☞克隆

作者: 小明今晚加班 | 来源:发表于2019-05-29 21:30 被阅读0次

在基类Object中,有个clone方法,可产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,又有了深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆将会将此属性完全拷贝一份;而浅克隆仅仅是拷贝一份此属性的引用。其实在克隆的时候最需要注意的是对象和数组,这两种类型一定要铭记深度克隆的方法。

  1. clone方法是Object类的,并不是Cloneable接口的,Cloneable只是一个标记接口,标记接口是标记实现该接口的类具有某种该接口标记的功能。常见的标记接口有三个:Cloneable、Serializable、RandomAccess,如果没有实现Cloneable接口,那么调用clone方法就会报CloneNotSupportException异常。
  2. 重写clone方法,内部仅仅是调用了父类的clone方法,当然这只是浅克隆的clone方法,深克隆就要修改了。
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
  1. 给出一张前人画的克隆图,简直太容易理解了:


    浅克隆.png
    深克隆.png

给出两种深克隆的方法

1. 实现Cloneable接口,重写clone方法(需要嵌套clone方法)

package cn.ihep.clone;

import java.util.Arrays;

/**
 * 测试克隆---深度克隆,浅度克隆
 * 
 * @author xiaoming
 *
 */
public class CloneTest implements Cloneable {

    private String name;
    private int age;
    private String[] hobby;
    private int[] nums;

    public CloneTest(String name, int age, String[] hobby, int[] nums) {
        super();
        this.name = name;
        this.age = age;
        this.hobby = hobby;
        this.nums = nums;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }

    public int[] getNums() {
        return nums;
    }

    public void setNums(int[] nums) {
        this.nums = nums;
    }

    @Override
    protected Object clone() {
        CloneTest clt = null;
        try {
            clt = (CloneTest) super.clone();
            //这里必须要加上hobby和nums的克隆(数组和对象都需要添加该方法)
            clt.hobby = hobby.clone();
            clt.nums = nums.clone();
            return clt;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clt;
    }

    @Override
    public String toString() {
        return "CloneTest [name=" + name + ", age=" + age + ", hobby=" + Arrays.toString(hobby) + ", nums="
                + Arrays.toString(nums) + "]";
    }

    public static void main(String[] args) {
        String name = "xiaoming";
        int age = 17;
        String[] strs = { "a", "b" };
        int[] nums = { 1, 2, 3 };
        CloneTest t = new CloneTest(name, age, strs, nums);
        CloneTest tNew = (CloneTest) t.clone();
        System.out.println(t);
        System.out.println(tNew);
        nums[0] = 250;
        strs[0] = "hahah";
        t.setNums(nums);
        t.setHobby(strs);
        System.out.println(t);
        System.out.println(tNew);
    }
}
-----------------
输出结果 :
CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
CloneTest [name=xiaoming, age=17, hobby=[hahah, b], nums=[250, 2, 3]]
CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]

2. 通过序列化的方法来实现深度克隆

使用这种方法的时候,克隆的对象一定要实现Serializable接口。

package cn.ihep.clone;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;

/**
 * 通过序列化来实现深度克隆
 * 
 * @author xiaoming
 *
 */
public class CloneBySerializable implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    private String[] hobby;
    private int[] nums;

    public CloneBySerializable(String name, int age, String[] hobby, int[] nums) {
        super();
        this.name = name;
        this.age = age;
        this.hobby = hobby;
        this.nums = nums;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }

    public int[] getNums() {
        return nums;
    }

    public void setNums(int[] nums) {
        this.nums = nums;
    }

    @Override
    public String toString() {
        return "CloneTest [name=" + name + ", age=" + age + ", hobby=" + Arrays.toString(hobby) + ", nums="
                + Arrays.toString(nums) + "]";
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String name = "xiaoming";
        int age = 17;
        String[] strs = { "a", "b" };
        int[] nums = { 1, 2, 3 };
        CloneBySerializable t = new CloneBySerializable(name, age, strs, nums);
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(t);
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        CloneBySerializable cloneT = (CloneBySerializable) oi.readObject();
        System.out.println(t);
        System.out.println(cloneT);
        nums[0] = 250;
        strs[0] = "hahah";
        t.setNums(nums);
        t.setHobby(strs);
        System.out.println(t);
        System.out.println(cloneT);
    }
}
--------------------------------
输出结果:
CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
CloneTest [name=xiaoming, age=17, hobby=[hahah, b], nums=[250, 2, 3]]
CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]

通过序列化的方法来实现深克隆还是一个比较常用的操作,比如有一个列表list,里面存储的是User对象,即List<User> list = new ArrayList<>();如果想把列表list给拷贝一份给cloneList,该如何操作呢?
这个时候序列化的方式首选,前提User类要实现Serializable接口。如下:

package cn.ihep.clone;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.internal.compiler.batch.Main;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;

    public User(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User u1 = new User("xiaoming", 18);
        User u2 = new User("ahua", 45);
        User u3 = new User("zhangsan", 19);
        User u4 = new User("lisi", 20);
        List<User> list = new ArrayList<>();
        list.add(u1);
        list.add(u2);
        list.add(u3);
        list.add(u4);

        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(list);

        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        List<User> cloneList = (List<User>) oi.readObject();
        System.out.println(list);
        System.out.println(cloneList);
        
        list.get(0).setName("zhaoxiaoming");
        list.get(0).setAge(100);
        System.out.println(list);
        System.out.println(cloneList);
    }
}
--------------------------------
输出结果:
[User [name=xiaoming, age=18], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]
[User [name=xiaoming, age=18], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]
[User [name=zhaoxiaoming, age=100], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]
[User [name=xiaoming, age=18], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]

注意:String类型的变量在克隆时候外表效果看起来和基本数据类型一样,其实不是这样的,因为String类型是不可改变类型,所以,当你修改字符串str的值的时候,是直接在堆上又new出来了一个对象,同时你的引用地址也跟着指向这个新地址了,所以看起来“貌似”不符合上述对象克隆的特征,事实上他们并冲突,就是因为String类型特殊。

相关文章

  • 使用对象序列化和反序列化实现深度克隆

    java对象进行克隆,分为浅克隆和深克隆 浅克隆需要实现java.lang.Cloneable接口,并重写java...

  • java克隆

    java克隆 java克隆分为浅克隆和深克隆,概念如下: 浅拷贝(浅克隆)克隆出来的对象的所有变量都含有与原来的对...

  • Java深复制浅复制解析.md

    Java 克隆概念 Java克隆分为深克隆和浅克隆两种类型。 浅复制(浅克隆)被复制对象的所有变量都含有与原来的对...

  • JAVA之假克隆、浅克隆、深克隆

    一.JAVA假克隆 Java中,对于基本类型,可以用“=”进行克隆,而对于引用类型却不能简单的使用“=”进行克隆,...

  • Java☞克隆

    在基类Object中,有个clone方法,可产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,又...

  • Java 深克隆&浅克隆

    Java 深克隆(DeepClone)与浅克隆(ShallowClone)是原型设计模式的灵魂。记录结构:--什么...

  • 理解Java浅克隆和深克隆

    克隆概念 Java一切皆对象,克隆就是对对象的克隆;克隆可能听起来有点高级,也可以为对象复制或者对象拷贝。平时开发...

  • Java基础 - 深拷贝和浅拷贝

    Java 的深拷贝和浅拷贝 什么是深拷贝、浅拷贝 (深克隆、浅克隆)? 在 Java 中,数据类型分为 基本数据类...

  • Java 浅克隆、深克隆

    浅克隆 只复制了基本数据类型和String数据类型以及对应的数组类型,其他引用数据类型只是复制了引用地址; 使用方...

  • 震惊!没看这篇文章之前,我以为真的懂深克隆和浅克隆。

    面试题:深克隆和浅克隆的实现方式 面试官考察点 考察目的: 深克隆和浅克隆,考察的是Java基础知识的理解。 考察...

网友评论

      本文标题:Java☞克隆

      本文链接:https://www.haomeiwen.com/subject/ukvutctx.html