GVKun编程网logo

Java深、浅克隆(clone)(java深浅克隆的原理区别)

11

如果您想了解Java深、浅克隆(clone)和java深浅克隆的原理区别的知识,那么本篇文章将是您的不二之选。我们将深入剖析Java深、浅克隆(clone)的各个方面,并为您解答java深浅克隆的原理

如果您想了解Java深、浅克隆(clone)java深浅克隆的原理区别的知识,那么本篇文章将是您的不二之选。我们将深入剖析Java深、浅克隆(clone)的各个方面,并为您解答java深浅克隆的原理区别的疑在这篇文章中,我们将为您介绍Java深、浅克隆(clone)的相关知识,同时也会详细的解释java深浅克隆的原理区别的运用方法,并给出实际的案例分析,希望能帮助到您!

本文目录一览:

Java深、浅克隆(clone)(java深浅克隆的原理区别)

Java深、浅克隆(clone)(java深浅克隆的原理区别)

    Java的基类Object中有个本地方法clone(),由于该方法是protected访问权限,所以只能在Object内部或其子类内部访问,可是不能在类外通过对象.clone()访问。

 protected native Object clone() throws CloneNotSupportedException;

    自定义的类需要实现"克隆",一定要实现Cloneable接口(该接口内没有任何方法,但如果不实现该接口就直接在类里调用Object的clone(),运行报错)。

    1、浅拷贝:

    需要实现拷贝的自定义User类

public class User implements Cloneable{
		private int id;
		private String name;

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

		@Override //这个注解有和没有都一样
		public User clone() throws CloneNotSupportedException {
			return (User)super.clone();//直接调用Object的clone(),并返回就可以了
		}
		
		public int getId() {
			return id;
		}
		
		public String getName() {
			return name;
		}
		
	}

    测试类:

public class TestClone {
	
	public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
		User u1 = new User(1, "zhangsan");
		User u2 = u1.clone();
		System.out.println(u1==u2);
		System.out.println(u1.getId()==u2.getId());
		System.out.println(u1.getName()==u2.getName());
	}
}

    结果:false、true、true

    可能很多人会觉得第三个应该是false。我们先来看一下Object类提供的拷贝机制,就会明白了。

    Object类提供的Clone机制只对对象里的各实例变量进行“简单复制”,如果实例变量的类型是引用类型(本例中的String name),也只是简单得复制这个引用变量(应该是这样:u2=u1),这样u1和u2仍然指向内存中的同一实例。如果需要引用类型的实例也拷贝一份,那就需要深拷贝了。

    2、深拷贝:    

    需要拷贝的User类还要实现 Serializable接口(也是没有任何方法的接口),因为要用到输入、输出流将对象实例从内存中复制一份。

    User类:

public class User implements Cloneable,Serializable{
		private int id;
		private String name;
		
		@Override
		public User clone() throws CloneNotSupportedException {
		    ByteArrayOutputStream baos = new ByteArrayOutputStream();//字节输出流
			ObjectOutputStream out = new ObjectOutputStream(baos);//对象输出流中嵌套封装字节输出流
			
			out.writeObject(this);//将调用clone()当前对象的数据输出保存在字节输出流中
			
			ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());//字节输入流,指定读取的数据来自baos中的字节
			ObjectInputStream in = new ObjectInputStream(bais);//对象输入流封装字节输入流
			
			User u = (User)in.readObject();//将数据以对象的形式读取
			return u;
		}
		
		public User(int id, String name) {
			super();
			this.id = id;
			this.name = name;
		}
		
		public int getId() {
			return id;
		}

		public String getName() {
			return name;
		}

	}

    测试类还是和上面的测试类一样,结果为:false,true,false

通过下图便可了解深拷贝的机制:

 

Java | 浅克隆与深克隆

Java | 浅克隆与深克隆

前言

克隆,即复制一个对象,该对象的属性与被复制的对象一致,如果不使用 Object 类中的 clone 方法实现克隆,可以自己 new 出一个对象,并对相应的属性进行数据,这样也能实现克隆的目的。

但当对象属性较多时,这样的克隆方式会比较麻烦,所以 Object 类中实现了 clone 方法,用于克隆对象,Java 中的克隆分为浅克隆与深克隆。

实现克隆的方式

1. 对象的类需要实现 Cloneable 接口

2. 重写 Object 类中的 clone () 方法

3. 根据重写的 clone () 方法得到想要的克隆结果,例如浅克隆与深克隆。


浅克隆与深克隆的区别

浅克隆:复制对象时仅仅复制对象本身,包括基本属性,但该对象的属性引用其他对象时,该引用对象不会被复制,即拷贝出来的对象与被拷贝出来的对象中的属性引用的对象是同一个。

深克隆:复制对象本身的同时,也复制对象包含的引用指向的对象,即修改被克隆对象的任何属性都不会影响到克隆出来的对象。


 

例子如下:

class Person implements Cloneable{

private int age;
private String name;

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

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

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

@Override
public String toString() {
return "Person{" +
"age=" + age +
", name=''" + name + ''\'''' +
''}'';
}

@Override
protected Person clone() throws CloneNotSupportedException {
return (Person)super.clone(); //调用父类的clone方法
}
}


测试代码:

public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person(22,"LiLei");
Person newPerson = person.clone();
person.setAge(21);
person.setName("HanMeimei");
System.out.println(person.toString());
System.out.println(newPerson.toString());
}
}


测试结果:

Person{age=21, name=''HanMeimei''}Person{age=22, name=''LiLei''}

即在克隆出新的对象后,修改被克隆对象的基本属性,并不会影响克隆出来的对象。但当被克隆的对象的属性引用其他对象时,此时会有不同的结果。

例子如下:

/**
* 学生类
*/

class Student implements Cloneable{
private String name;
private Achievement achievement; //成绩

public Student(String name, Achievement achievement) {
this.name = name;
this.achievement = achievement;
}

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

public void setAchievement(Achievement achievement) {
this.achievement = achievement;
}

public Achievement getAchievement() {
return achievement;
}

@Override
public String toString() {
return "Student{" +
"name=''" + name + ''\'''' +
", achievement=" + achievement +
''}'';
}

@Override
protected Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}

/**
* 成绩类
*/

class Achievement implements Cloneable{
private float Chinese;
private float math;
private float English;

public Achievement(float chinese, float math, float english) {
Chinese = chinese;
this.math = math;
English = english;
}

public void setChinese(float chinese) {
Chinese = chinese;
}

public void setMath(float math) {
this.math = math;
}

public void setEnglish(float english) {
English = english;
}

@Override
public String toString() {
return "Achievement{" +
"Chinese=" + Chinese +
", math=" + math +
", English=" + English +
''}'';
}

@Override
protected Achievement clone() throws CloneNotSupportedException {
return (Achievement) super.clone();
}
}

测试代码:

public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Achievement achievement = new Achievement(100,100,100);
Student student = new Student("LiLei",achievement);
// 克隆出一个对象
Student newStudent = student.clone();

// 修改原有对象的属性
student.setName("HanMeimei");
student.getAchievement().setChinese(90);
student.getAchievement().setEnglish(90);
student.getAchievement().setMath(90);

System.out.println(newStudent);
System.out.println(student);

}
}


测试结果:

Student{name=''LiLei'', achievement=Achievement{Chinese=90.0, math=90.0, English=90.0}}Student{name=''HanMeimei'', achievement=Achievement{Chinese=90.0, math=90.0, English=90.0}}

以上现象表明,上述克隆方式为浅克隆,并不会克隆对象的属性引用的对象,当修改被克隆对象的成绩时,克隆出来的对象也会跟着改变,即两个对象的属性引用指向的是同一个对象。

但只要修改一下 Student 类中重写的 clone () 方法,即可实现深克隆。

修改代码如下:

@Override
protected Student clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
Achievement achievement = student.getAchievement().clone();
student.setAchievement(achievement);
return student;
}


 测试结果:

Student{name=''LiLei'', achievement=Achievement{Chinese=100.0, math=100.0, English=100.0}}Student{name=''HanMeimei'', achievement=Achievement{Chinese=90.0, math=90.0, English=90.0}}

 即在 Student 类中的 clone () 方法中再克隆一次 Achievement 对象,并赋值给 Student 对象。

值得一提的是,上文所说的浅拷贝只会克隆基本数据属性,而不会克隆引用其他对象的属性,但 String 对象又不属于基本属性,这又是为什么呢?

这是因为 String 对象是不可修改的对象,每次修改其实都是新建一个新的对象,而不是在原有的对象上修改,所以当修改 String 属性时其实是新开辟一个空间存储 String 对象,并把引用指向该内存,而克隆出来的对象的 String 属性还是指向原有的内存地址,所以 String 对象在浅克隆中也表现得与基本属性一样。

推荐阅读:

1、java | 什么是动态代理

2、实用工具 | 推荐 9 个 chrome 扩展

3、springboot | 自动配置原理


本文分享自微信公众号 - 一个优秀的废人(feiren_java)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与 “OSC 源创计划”,欢迎正在阅读的你也加入,一起分享。

Java 中如何使用clone()方法克隆对象?

Java 中如何使用clone()方法克隆对象?

java为什么要 对象克隆:

 

在程序开发时,有时可能会遇到以下情况:已经存在一个对象A,现在需要一个与A对象完全相同的B 对象,并对B 对象的属性值进行修改,但是A 对象原有的属性值不能改变。这时,如果使用Java 提供的对象赋值语句,当修改B 对象的属性值后,A 对象的属性值也将被修改。那么应该如何实现创建一个与A 对象完全相同的B 对象,但是改变B对象的属性值时A 对象的属性值不变呢?

 

专家解答

要实现这一功能,可以使用Object 类中的clone()方法。clone()方法可以用来完成对象的浅克隆。所谓浅克隆就是说被克隆的对象各个属性都是基本类型,而不是引用类型。如果存在引用类型的属性,则需要进行深克隆。下面对这两种克隆方式进行举例说明。

1.浅克隆(1)编写Address 类,首先在该类中定义state(表示国家)、province(表示省)和city(表示市)3 个域,然后在构造方法中初始化这3 个域,并提供getter()和setter()方法用于获得和修改这3 个域,最后重写toString()方法方便输出该类的对象,代码如下:

 

 

 

1.浅克隆(1)编写Address 类,首先在该类中定义state(表示国家)、province(表示省)和city(表示市)3 个域,然后在构造方法中初始化这3 个域,并提供getter()和setter()方法用于获得和修改这3 个域,最后重写toString()方法方便输出该类的对象,代码如下:

地址对象:

package com.nf147.Constroller;

public class Address implements Cloneable {
    private String state;            //国家
    private String province;         //
    private String city;            //市

    public Address() {
    }

    public Address(String state, String province, String city) {
        this.state = state;
        this.province = province;
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {                  //重写toString
        StringBuilder sb=new StringBuilder();
        sb.append("国家:"+state+",");
        sb.append("省:"+province+",");
        sb.append("市:"+city+",");
        return sb.toString();
    }
}

 

 编写Employee 类,首先在该类中定义name(表示姓名)、age(表示年龄)和address(表示地址)3 个域,然后在构造方法中初始化这3 个域,并提供getter()和setter()方法用于获得和修改这3 个域,再重写toString()方法方便输出该类的对象,最后重写clone()方法来提供克隆的功能,代码如下:

员工:

package com.nf147.Constroller;

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;
    }

    public Employee() {
    }

    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 Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {   //重新toString()方法
        return "Employee{" +
                "姓名=''" + name + ''\'''' +
                ", 年龄=" + age +
                ", 地址=" + address +
                ''}'';
    }

    public Employee clone() {           //实现浅克隆
        Employee employee = null;
        try {
            employee = (Employee) super.clone();
            employee.address = address.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return employee;
    }


}

 

测试类:

package com.nf147.Constroller;

public class TestClone {
    public static void main(String[] args) {
        System.out.println("克隆之前:");
        Address address = new Address("中国", "吉林", "长春");
        Employee employee1 = new Employee("无语", 32, address);
        System.out.println("员工 1 的信息");
        System.out.println(employee1);

        System.out.println("====================");
        System.out.println("克隆之后:");

        Employee employee2=employee1.clone();
        employee2.getAddress().setState("中国");
        employee2.getAddress().setProvince("辽宁");
        employee2.getAddress().setCity("大连");
        employee2.setName("倾城");
        employee2.setAge(33);
        System.out.println("员工2 的 信息");
        System.out.println(employee2);
        System.out.println("员工1的 信息");
        System.out.println(employee1);
    }
}

 

截图:

 

 

 

说明:

从图中可以看到,对于引用类型并没有克隆成功。

 

2.深克隆(1)编写类Address1,在该类中首先定义state(表示国家)、province(表示省)和city(表示市)3 个域,然后在构造方法中初始化这3 个域,并提供了getter()和setter()方法用于获得和修改这3 个域,再重写toString()方法方便输出该类的对象,最后重写clone()方法提供克隆的功能,关键代码如下:

package com.nf147.Constroller;

public class Address implements Cloneable {
    private String state;            //国家
    private String province;         //
    private String city;            //市

    public Address() {
    }

    public Address(String state, String province, String city) {
        this.state = state;
        this.province = province;
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {                  //重写toString
        StringBuilder sb=new StringBuilder();
        sb.append("国家:"+state+",");
        sb.append("省:"+province+",");
        sb.append("市:"+city+",");
        return sb.toString();
    }

    @Override
    protected Address clone(){
        Address address = null;
        try{
            address=(Address)super.clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return address;
    }
}

 

说明:

Address 类的域不是基本类型就是不可变类型,所以可以直接使用浅克隆。

(2)编写Employee类,首先在该类中定义name(表示姓名)、age(表示年龄)和address(表示地址)3 个域,然后在构造方法中初始化这3 个域,并提供getter()和setter()方法用于获得和修改这3 个域,再重写toString()方法方便输出该类的对象,最后重写clone()方法来提供克隆的功能。代码如下:

 

package com.nf147.Constroller;

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;
    }

    public Employee() {
    }

    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 Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {   //重新toString()方法
        return "Employee{" +
                "姓名=''" + name + ''\'''' +
                ", 年龄=" + age +
                ", 地址=" + address +
                ''}'';
    }

    public Employee clone() {           //实现浅克隆
        Employee employee = null;
        try {
            employee = (Employee) super.clone();
            employee.address = address.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return employee;
    }


}

测试:

package com.nf147.Constroller;

public class TestClone {
    public static void main(String[] args) {
        System.out.println("克隆之前:");
        Address address = new Address("中国", "吉林", "长春");
        Employee employee1 = new Employee("无语", 32, address);
        System.out.println("员工 1 的信息");
        System.out.println(employee1);

        System.out.println("====================");
        System.out.println("克隆之后:");

        Employee employee2=employee1.clone();
        employee2.getAddress().setState("中国");
        employee2.getAddress().setProvince("辽宁");
        employee2.getAddress().setCity("大连");
        employee2.setName("倾城");
        employee2.setAge(33);
        System.out.println("员工2 的 信息");
        System.out.println(employee2);
        System.out.println("员工1的 信息");
        System.out.println(employee1);
    }
}

 

 

截图:

 

Java 中对象的深克隆和浅克隆

Java 中对象的深克隆和浅克隆

浅克隆和深克隆的概念

        浅克隆:被克隆的对象里的所有变量值都与原来的对象相同,而所有对其他对象的引用仍然指向原来的对象。简而言之,浅克隆仅仅克隆当前对象,而不克隆当前对象所引用的对象。

        深克隆:被克隆的对象里的所有变量值都与原来的对象相同,那些引用其他对象的变量将指向被复制过的新对象,而不再是原来被引用的对象。简而言之,深克隆不仅克隆了当前对象,还把当前对象所引用的对象都复制了一遍。

 

Java 中的 clone () 方法

        Object 类中的 clone () 方法属于浅克隆。它的工作原理是:先在内存中开辟一块和原始对象相同大小的空间,然后原样复制原始对象中的内容。对于基本数据类型,这样操作是没问题的。但对于非基本数据类型,由于它们所保存的仅仅是对象的引用,如果不进行更深层次的克隆,就会导致克隆后的对象引用和原始对象中相应的对象引用所指向的是同一个对象。

 

使用 clone () 方法实现浅克隆

        在要克隆的类中实现 Cloneable 接口,覆盖 Object 类中的 clone () 方法,并声明为 public。同时在 clone () 方法中,调用 super.clone () 返回克隆后的对象。请看以下代码:

class Professor {
    String name;
    int age;

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

class Student implements Cloneable {
    String name;
    int age;
    Professor professor;

    public Student(String name, int age, Professor professor) {
        this.name = name;
        this.age = age;
        this.professor = professor;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }
}

public class CloneTutorial {
    public static void main(String[] args) throws CloneNotSupportedException {
        Professor professor = new Professor("Galler", 50);
        Student student1 = new Student("Tom", 18, professor);
        Student student2 = student1.clone();

        System.out.println("Before change student2''s professor");
        System.out.println("Student1''s professor name = " + student1.professor.name);
        System.out.println("student1''s professor age = " + student1.professor.age);

        student2.professor.name = "Mary";
        student2.professor.age = 30;

        System.out.println();
        System.out.println("After change student2''s professor");
        System.out.println("Student1''s professor name = " + student1.professor.name);
        System.out.println("Student1''s professor age = " + student1.professor.age);
    }
}

 

使用 clone () 方法实现深克隆

        通过以上代码可以证明 Java 中的 clone () 方法是浅克隆,那应该如何实现更深层次的克隆呢?请看以下代码:

class Professor implements Cloneable {
    String name;
    int age;

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

    @Override
    protected Professor clone() throws CloneNotSupportedException {
        return (Professor) super.clone();
    }
}

class Student implements Cloneable {
    String name;
    int age;
    Professor professor;

    public Student(String name, int age, Professor professor) {
        this.name = name;
        this.age = age;
        this.professor = professor;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.professor = student.professor.clone();
        return student;
    }
}

public class CloneTutorial {
    public static void main(String[] args) throws CloneNotSupportedException {
        Professor professor = new Professor("Galler", 50);
        Student student1 = new Student("Tom", 18, professor);
        Student student2 = student1.clone();

        System.out.println("Before change student2''s professor");
        System.out.println("Student1''s professor name = " + student1.professor.name);
        System.out.println("student1''s professor age = " + student1.professor.age);

        student2.professor.name = "Mary";
        student2.professor.age = 30;

        System.out.println();
        System.out.println("After change student2''s professor");
        System.out.println("Student1''s professor name = " + student1.professor.name);
        System.out.println("Student1''s professor age = " + student1.professor.age);
    }
}

        在以上代码中,虽然通过在 Student 类中调用 Professor 类中覆盖的 clone 方法来对 professor 成员进行克隆从而实现了深克隆,但也由此可见,如果克隆类中的引用类型变量有多个的情况下,采用这种方式实现深克隆将会非常复杂。

 

使用对象序列化和反序列化实现深克隆(推荐

        把对象写到字节流里的过程是序列化(Serilization)的过程,而把对象从字节流中读出来的过程是反序列化(Deserialization)的过程。由于在 Java 序列化的过程中,写在流里的是对象的一个拷贝,而原对象仍然在 JVM 里,所以可以利用这个原理来实现对对象的深克隆。请看以下代码:

class Professor implements Serializable {
    String name;
    int age;

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

class Student implements Serializable {
    String name;
    int age;
    Professor professor;

    public Student(String name, int age, Professor professor) {
        this.name = name;
        this.age = age;
        this.professor = professor;
    }

    public Student deepClone() throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(this);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        return (Student) objectInputStream.readObject();
    }
}

public class CloneTutorial {
    public static void main(String[] args) throws Exception {
        Professor professor = new Professor("Galler", 50);
        Student student1 = new Student("Tom", 18, professor);
        Student student2 = student1.deepClone();

        System.out.println("Before change student2''s professor");
        System.out.println("Student1''s professor name = " + student1.professor.name);
        System.out.println("student1''s professor age = " + student1.professor.age);

        student2.professor.name = "Mary";
        student2.professor.age = 30;

        System.out.println();
        System.out.println("After change student2''s professor");
        System.out.println("Student1''s professor name = " + student1.professor.name);
        System.out.println("Student1''s professor age = " + student1.professor.age);
    }
}

 

总结

        虽然使用 Java 的 clone () 方法实现浅克隆以及深克隆更加直观,但是针对每一个需要克隆的类都必须单独实现一个 clone () 方法,导致其扩展性并不好。而使用对象序列化与反序列化来实现深克隆,能使代码更简洁,更通用。此处推荐使用后者。

Java 中的深克隆和浅克隆

Java 中的深克隆和浅克隆

为什么要克隆

首先思考一个问题,为什么需要克隆对象?直接 new 一个对象不行吗?

克隆的对象可能包含一些已经修改过的属性,而 new 出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的 "状态" 时就要靠克隆了.

当然,把对象的属性一个一个的赋值给新 new 的对象也是可以的,但是这样一来麻烦不说,二来,我们通过源码查看 Object 的 clone 方法是一个 native 方法 (native 方法是非 Java 语言实现的代码,供 Java 程序调用,要想访问比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现), 就是快啊,实在更底层实现的.

我们常见的 Object a = new Object (); Object b; b = a; 这种形式的代码复制的是引用,即对象在内存中的地址,a 和 b 指向了同一个对象。而通过 clone 方法赋值的对象跟原来的对象是同时独立存在的.

概念

浅克隆:

被克隆的对象里的所有变量值都与原来的对象相同,而所有对其他对象的引用仍然指向原来的对象。简单说,浅克隆仅克隆当前对象,而不克隆当前对象所引用的对象.

深克隆:

被克隆的对象里的所有变量值都与原来的对象相同,那些引用其他对象的变量将指向被复制过的新对象,而不再是原来被引用的对象。简单说,深克隆不仅克隆了当前对象,还把当前对象所引用的对象都复制了一遍.

Object 中的 clone

Object 类中的 clone () 方法属于浅克隆。它的工作原理如下:在内存中先开辟一块和原始对象相同的空间,然后复制原始对象的内容。对于基本数据类型,这样操作当然没问题,但对于引用类型,由于保存的仅仅是对象的引用,克隆过去的引用所指向的是同一个对象.

Java 中实现浅克隆

java 中实现 clone 要实现 Cloneable 接口,该接口十分简单,源码如下:

Java中的深克隆和浅克隆

 

仅仅起到一个标识的作用.

下面是一个实现浅克隆的例子:

Java中的深克隆和浅克隆

 

可以看到,对象确实不是原来的对象了,但是其中的引用对象却还是原来的对象.

浅克隆对于引用对象仅拷贝引用.

如果一个对象只包含原始数据或者不可变对象域 (如: String), 推荐使用浅克隆.

Java 中实现深克隆

将类中的所有引用类型都进行 clone, 并重写对象 clone () 方法,对所有引用类型进行 clone.

代码如下:

Java中的深克隆和浅克隆

 

将所有引用类型都进行 clone, 实现了深克隆.

Java 序列化克隆

如果引用类型中海包括引用类型,要实现多层克隆会很麻烦,这使用可以使用序列化和反序列化的方式实现对象的深克隆.

把对象写到字节流中的过程是序列化的过程,而把对象从字节流中读出来的过程是反序列化的过程。由于 Java 序列化的过程中,写在流中的是对象的一个拷贝,而原对象仍然在 JVM 中,所以可以利用这个原理来实现对对象的深克隆.

上面代码使用序列化实现如下:

Java中的深克隆和浅克隆

 

可以将序列化克隆封装为一个方法,如下所示:

Java中的深克隆和浅克隆

 

通过该工具类即可进行深度克隆。要是用该方法,对象、对象的所有引用类型、引用类型中的引用类型都要实现 Serializable 接口.


当然,对象中的 final 对象是不能进行 clone 的,因为 final 的限制.

如果用线程安全的类实现 Cloneable, 要保证它的 clone 方法做好同步工作,默认的 Object.clone 方法是没有同步的.

今天的关于Java深、浅克隆(clone)java深浅克隆的原理区别的分享已经结束,谢谢您的关注,如果想了解更多关于Java | 浅克隆与深克隆、Java 中如何使用clone()方法克隆对象?、Java 中对象的深克隆和浅克隆、Java 中的深克隆和浅克隆的相关知识,请在本站进行查询。

本文标签:

上一篇深入理解Tomcat系列之三:Connector(tomcat的connector)

下一篇【1】Dockerizing Applications:A "Hello world"(docker in practice)