精华内容
下载资源
问答
  • Cloneable接口作用与深克隆、浅克隆的理解 文章目录Cloneable接口作用与深克隆、浅克隆的理解一、简介1. 为什么需要克隆2. Cloneable接口作用3. 如何实现克隆二、浅克隆和深克隆介绍三、代码演示1. 浅克隆2. ...

    Cloneable接口的作用与深克隆、浅克隆的理解

    一、简介

    1. 为什么需要克隆

    • 使用new的方式创建一个对象,这个对象是一个全新的对象,对应的属性值都是在堆空间中的默认值,所以还需要手动的给这个对象的所有属性赋予值
    • 如果想要一个新的对象保存当前对象的属性值及方法(创建当前对象的副本),就需要通过克隆方法
    • 把new出来的对象的属性一个一个的赋值也是可以的,但是一来麻烦,二来,clone方法是一个native方法,速度很快

    2. Cloneable接口的作用

    • Cloneable是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类创建的对象调用clone方法才能克隆成功,如果不实现这个接口,则会抛出 CloneNotSupportedException (克隆不被支持) 异常

    • Object类中的clone方法

      • protected native Object clone() throws CloneNotSupportedException;

    3. 如何实现克隆

    • 对象的类实现Cloneable接口
    • 重写Object类的clone()方法
    • 在clone()方法中调用super.clone();

    二、浅克隆和深克隆介绍

    • 浅克隆是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用类型指向的对象,即拷贝之后属性中的引用类型指向的地址没有改变,两个对象的此引用类型的属性同步变化

      • 如果是String类型的话,不会同步变化,因为String类的不可变性,修改了String类型的值,会新创建一个String类型对象,对原来的没有影响
      image-20210405095656580
    • 深克隆不仅拷贝对象本身,而且拷贝对象包含的引用类型指向的对象,即拷贝之后属性中的引用类型会指向一个新的地址,一个对象中的此引用类型的属性改变不会影响到另一个对象

      image-20210405095831576

    三、代码演示

    1. 浅克隆

    • 创建Student.java
    public class Student implements Cloneable{
        private int age;
        private String name;
        
        //getter、setter、构造器、toString
    
        @Override
        protected Student clone() throws CloneNotSupportedException {
            return (Student) super.clone();
        }
    }
    
    • 创建School.java
    public class School implements Cloneable{
        private String location;
        private Student student;
    
        //getter、setter、构造器、toString
        
        @Override
        protected School clone() throws CloneNotSupportedException {
            return (School) super.clone();
        }
    }
    
    • 创建测试类
    public class Test {
        public static void main(String[] args) throws CloneNotSupportedException {
            Student student = new Student(22, "周杰伦");
            School s1 = new School("山西", student);
            School s2 = s1.clone();
            System.out.println(s1 + ",s1的地址值:" + s1.hashCode() +
                    ",s1中的Student对象的地址值:" + s1.getStudent().hashCode());
            System.out.println(s2 + ",s2的地址值:" + s2.hashCode() +
                    ",s2中的Student对象的地址值:" + s2.getStudent().hashCode());
        }
    }
    

    运行结果:

    image-20210405102048235

    2. 深克隆

    • 修改School.java中的clone方法
    @Override
    protected School clone() throws CloneNotSupportedException {
        School school = (School) super.clone();
        //将school中的student对象再克隆一份
        school.setStudent(school.getStudent().clone());
        return school;
    }
    

    运行结果:

    image-20210405102909230
    展开全文
  • 2.实现注意事项2.1 要调用 clone 方法必须实现 Cloneable 接口如果类没有实现 Cloneable 接口,类的实例却调用了 clone 方法,则会抛出CloneNotSupportedException异常。用反射机制去调用 Objec 类的 clone 方法,...

    JDK 版本:1.8

    代码地址

    1.前言

    clone方法能方便的获得一个对象的拷贝,但其中也有些细节需要注意。

    2.实现注意事项

    2.1 要调用 clone 方法必须实现 Cloneable 接口

    如果类没有实现 Cloneable 接口,类的实例却调用了 clone 方法,则会抛出CloneNotSupportedException异常。

    用反射机制去调用 Objec 类的 clone 方法,可以观察到这个现象:

    Object object = new Object();

    Method method = object.getClass().getDeclaredMethod("clone");

    method.setAccessible(true);

    method.invoke(object);

    运行结果:

    Caused by: java.lang.CloneNotSupportedException: java.lang.Object

    at java.lang.Object.clone(Native Method)

    2.2 clone 方法的默认实现是浅拷贝

    clone 方法的默认实现是拷贝,即对于类中可变对象没有进行真正的拷贝,只是将该可变对象赋值给了克隆对象对应的字段。修改当前对象中可变对象也会影响到克隆对象中相应的字段。

    举个例子来说明下:

    private static void shallowCopyTest() {

    Person ming = new Person("ming", new String[]{"mingMing", "daMing"});

    compareCloneObject(ming);

    }

    private static void compareCloneObject(Person person) {

    try {

    Person fakePerson = (Person) person.clone();

    System.out.println("person.getNickName() == fakePerson.getNickName() : "

    + (person.getNickName() == fakePerson.getNickName()));

    fakePerson.setNickName(0, "compare");

    System.out.println(person);

    System.out.println(fakePerson);

    } catch (CloneNotSupportedException e) {

    e.printStackTrace();

    }

    }

    private static class Person implements Cloneable {

    private String name;

    private String[] nickName;

    public Person(String name, String[] nickName) {

    this.name = name;

    this.nickName = nickName;

    }

    public void setNickName(int index, String nickName) {

    this.nickName[index] = nickName;

    }

    public void setNickName(String[] nickName) {

    this.nickName = nickName;

    }

    public String[] getNickName() {

    return nickName;

    }

    @Override

    public Object clone() throws CloneNotSupportedException {

    return super.clone();

    }

    @Override

    public String toString() {

    return "Person{" +

    "name='" + name + '\'' +

    ", nickName=" + Arrays.toString(nickName) +

    '}';

    }

    }

    调用shallowCopyTest方法,输出结果为:

    person.getNickName() == fakePerson.getNickName() : true

    Person{name='ming', nickName=[compare, daMing]}

    Person{name='ming', nickName=[compare, daMing]}

    可以看到原对象与克隆对象的 nickName 是同一个数组,更改一个以后另一个的值也发送相应变化。

    2.3 深拷贝的实现

    实现深拷贝要将对象类的所有可变对象都拷贝一遍,然后用拷贝的引用去替换掉原有的引用。

    实现例子如下:

    private static void deepCopyTest() {

    Student ming = new Student("ming", new String[]{"mingMing", "daMing"}, "jiangNan");

    compareCloneObject(ming);

    }

    public static class Student extends Person {

    private String school;

    public Student(String name, String[] nickName, String school) {

    super(name, nickName);

    this.school = school;

    }

    @Override

    public Object clone() throws CloneNotSupportedException {

    Student student = (Student) super.clone();

    student.setNickName(this.getNickName().clone());

    return student;

    }

    @Override

    public String toString() {

    return "Student{" +

    "name='" + super.name + '\'' +

    ", nickName=" + Arrays.toString(super.nickName) +

    ", school='" + school + '\'' +

    '}';

    }

    }

    调用deepCopyTest方法,输出结果为:

    person.getNickName() == fakePerson.getNickName() : false

    Student{name='ming', nickName=[mingMing, daMing], school='jiangNan'}

    Student{name='ming', nickName=[compare, daMing], school='jiangNan'}

    可以看到两个对象 nickName 已经不是同一个对象了,改变之后也不会相互影响了。这是因为在覆写的 clone 方法中对 nickName 数组也进行了克隆,并赋值给克隆对象。

    3.注释文档及个人翻译

    /**

    * A class implements the Cloneable interface to

    * indicate to the {@link java.lang.Object#clone()} method that it

    * is legal for that method to make a

    * field-for-field copy of instances of that class.

    *

    * 一个类实现了 Cloneable 接口表示该类使用clone()方法来实现实例的逐字段的复制是合法的。

    *

    * Invoking Object's clone method on an instance that does not implement the

    * Cloneable interface results in the exception

    * CloneNotSupportedException being thrown.

    *

    * 在一个没有实现 Cloneable 接口的实例上调用 clone 方法将会抛出CloneNotSupportedException。

    *

    * By convention, classes that implement this interface should override

    * Object.clone (which is protected) with a public method.

    * See {@link java.lang.Object#clone()} for details on overriding this

    * method.

    * 按照惯例,实现该接口的类应该覆写Object.clone为一个公共方法。查看java.lang.Object#clone()

    * 来获取更多细节。

    *

    *

    * Note that this interface does not contain the clone method.

    * Therefore, it is not possible to clone an object merely by virtue of the

    * fact that it implements this interface. Even if the clone method is invoked

    * reflectively, there is no guarantee that it will succeed.

    * 注意:本接口不包含 clone 方法。因此,不能仅凭仅仅实现了本接口来克隆对象,即使是反射式调用,

    * 也不能保证成功。

    * @author unascribed

    * @see java.lang.CloneNotSupportedException

    * @see java.lang.Object#clone()

    * @since JDK1.0

    */

    /**

    * Creates and returns a copy of this object. The precise meaning

    * of "copy" may depend on the class of the object. The general

    * intent is that, for any object {@code x}, the expression:

    *

    *

    
      

    * x.clone() != x

    * will be true, and that the expression:

    *

    *

    
      

    * x.clone().getClass() == x.getClass()

    * will be {@code true}, but these are not absolute requirements.

    * While it is typically the case that:

    *

    *

    
      

    * x.clone().equals(x)

    * will be {@code true}, this is not an absolute requirement.

    *

    * 创建并返回一个对象的拷贝。拷贝的准确定义取决于对象的类定义。普遍的来说,对任意对象 x,

    * 表达式:x.clone() ! = x 的值是 true,并且表达式:x.clone().getClass() == x.getClass()

    * 的值是

    * true,但这些要求并不是绝对的。并且通常表达式:x.clone().equals(x)的值也是 true,

    * 这也不是绝对必要的条件。

    *

    * By convention, the returned object should be obtained by calling

    * {@code super.clone}. If a class and all of its superclasses (except

    * {@code Object}) obey this convention, it will be the case that

    * {@code x.clone().getClass() == x.getClass()}.

    *

    * 按照惯例,应该通过调用 super.clone 来获取返回的对象。如果一个类及其所有超类(Object 除外)

    * 都遵循此约定,则 x.clone().getClass() == x.getClass() 成立。

    *

    * By convention, the object returned by this method should be independent

    * of this object (which is being cloned). To achieve this independence,

    * it may be necessary to modify one or more fields of the object returned

    * by {@code super.clone} before returning it. Typically, this means

    * copying any mutable objects that comprise the internal "deep structure"

    * of the object being cloned and replacing the references to these

    * objects with references to the copies. If a class contains only

    * primitive fields or references to immutable objects, then it is usually

    * the case that no fields in the object returned by {@code super.clone}

    * need to be modified.

    *

    * 按照惯例,被本方法返回的对象应该与被克隆的原本对象无关。为了实现这种独立,可能需要在

    * 克隆方法返回前修改被返回对象的字段。通常,这意味着拷贝构成被克隆对象的内部“深度结构”

    * 的任何可变对象,并用拷贝的引用替换掉原本对象的引用。如果一个类仅仅包含原始字段或不可

    * 变对象的引用,那么通常super.clone返回对象中没有字段需要被修改。

    *

    * The method {@code clone} for class {@code Object} performs a

    * specific cloning operation. First, if the class of this object does

    * not implement the interface {@code Cloneable}, then a

    * {@code CloneNotSupportedException} is thrown. Note that all arrays

    * are considered to implement the interface {@code Cloneable} and that

    * the return type of the {@code clone} method of an array type {@code T[]}

    * is {@code T[]} where T is any reference or primitive type.

    * Otherwise, this method creates a new instance of the class of this

    * object and initializes all its fields with exactly the contents of

    * the corresponding fields of this object, as if by assignment; the

    * contents of the fields are not themselves cloned. Thus, this method

    * performs a "shallow copy" of this object, not a "deep copy" operation.

    *

    * Object 类的 clone 方法执行特定的克隆操作。首先,如果对象的类没有实现 Cloneable

    * 接口,那么会抛出 CloneNotSupportedException 异常。请注意,所有的数组都被视为实

    * 现了 Cloneable 接口,并且 T[] 类型数组 clone 接口的返回类型是 T[],此处 T 可以

    * 是任意引用类型或原始类型。除此之外,此方法创建一个对象的类的新实例,然后用原本对象对

    * 应字段内容来初始化新实例所有字段,就像赋值;字段的内容不会被克隆。因此,此方法对对象

    * 执行了“浅拷贝”而不是一个“深拷贝”。

    *

    * The class {@code Object} does not itself implement the interface

    * {@code Cloneable}, so calling the {@code clone} method on an object

    * whose class is {@code Object} will result in throwing an

    * exception at run time.

    * Object 类自身没有实现 Cloneable 接口,所以当对一个 Object 类的实例调用 clone

    * 方法时将会在运行时抛出异常。

    * @return a clone of this instance.

    * @throws CloneNotSupportedException if the object's class does not

    * support the {@code Cloneable} interface. Subclasses

    * that override the {@code clone} method can also

    * throw this exception to indicate that an instance cannot

    * be cloned.

    * @see java.lang.Cloneable

    */

    protected native Object clone() throws CloneNotSupportedException;

    展开全文
  • Cloneable 接口指示了一个类提供了一个安全的clone方法。首先了解Object.clone()方法:clone是Object超类的一个protected方法,用户代码不能直接调用这个方法。Object的子类只能调用Object超类中受保护的clone方法来...

    Cloneable 接口指示了一个类提供了一个安全的clone方法。

    首先了解Object.clone()方法:

    clone是Object超类的一个protected方法,用户代码不能直接调用这个方法。Object的子类只能调用Object超类中受保护的clone方法来克隆它自己的对象,必须重新定义clone为public才能允许所有方法调用这个类的实例的clone方法克隆对象。

    clone方法的作用:clone方法对Employee调用它对这个对象一无所知,所以只能逐个域地进行拷贝。a. 如果对象中的所有数据域都是数值或者其他基本类型,拷贝这些域没有问题;b. 但是如果对象中包含子对象的引用,拷贝域就会得到相同子对象的另一个引用(浅拷贝)。这样一来,原对象和克隆的对象仍然会共享一些信息。

    浅拷贝的影响:如果原对象和浅克隆对象共享的子对象是不可变的,那么这种共享就是安全的。如果子对象属于一个不可变的类,如String,就是这种情况。或者在对象的生命周期中,子对象一直包含不变的常量,没有更改器会改变它,就是没有方法会生成它的引用,这种情况同样是安全的(举个栗子:下面例子中hiereDay是一个Date对象,Date类的域是可变的,所以hireDay需要深拷贝。而LocalDate的域不可变,如果hireDay是不可变的LocaDate类的一个实例,就无需我们做任何处理了)。

    public class Employee implements Cloneable {

    private String name;

    private double salary;

    private Date hireDay;

    public Employee(String name, double salary)

    {

    this.name = name;

    this.salary = salary;

    hireDay = new Date();

    }

    @Override

    public Employee clone() throws CloneNotSupportedException

    {

    // call Object.clone() Employee cloned = (Employee) super.clone(); // clone会逐个域的进行拷贝

    // clone mutable fields cloned.hireDay = (Date) hireDay.clone();

    return cloned;

    }

    public void setHireDay(int year, int month, int day)

    {

    Date newHireDay = new GregorianCalendar(year, month - 1, day).getTime();

    // Example of instance field mutation hireDay.setTime(newHireDay.getTime());

    }

    public void raiseSalary(double byPercent)

    {

    double raise = salary * byPercent / 100;

    salary += raise;

    }

    public String toString()

    {

    return "Employee[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";

    }

    }

    public class Main {

    public static void main(String[] args)

    {

    Employee employee = new Employee("jack1", 20000);

    try {

    Employee clone = employee.clone();

    employee.raiseSalary(20);

    employee.setHireDay(2020, 10, 22);

    System.out.println(employee.toString());

    System.out.println(clone.toString());

    } catch (CloneNotSupportedException e) {

    e.printStackTrace();

    }

    }

    }

    /*** 输出:Employee[name=jack1,salary=24000.0,hireDay=Thu Oct 22 00:00:00 CST 2020]Employee[name=jack1,salary=20000.0,hireDay=Sun Oct 13 17:47:26 CST 2019]*/

    再看一个栗子,hireDay为不可变LocalDate类的实例时(private LocalDate hireDay;),Main.java类代码基本不变(构造函数有改变 -> Employee employee =newEmployee("jack1",20000,2019,10,13);):

    public class Employee implements Cloneable {

    private String name;

    private double salary;

    private LocalDate hireDay;

    public Employee(String name, double salary, int year, int month, int day)

    {

    this.name = name;

    this.salary = salary;

    hireDay = LocalDate.of(year, month, day);

    }

    @Override

    public Employee clone() throws CloneNotSupportedException

    {

    // call Object.clone() Employee cloned = (Employee) super.clone();

    // // clone mutable fields// cloned.hireDay = (Date) hireDay.clone();

    return cloned;

    }

    public void setHireDay(int year, int month, int day)

    {

    // Date newHireDay = new GregorianCalendar(year, month - 1, day).getTime();// // Example of instance field mutation// hireDay.setTime(newHireDay.getTime()); hireDay = LocalDate.of(year, month, day);

    }

    public void raiseSalary(double byPercent)

    {

    double raise = salary * byPercent / 100;

    salary += raise;

    }

    public String toString()

    {

    return "Employee[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";

    }

    }

    对于一个要实现clone方法的类,需要确定:实现Cloneable接口;

    重新定义clone方法,并且制定public访问修饰符。

    注意:

    Cloneable接口的出现与接口的正常实现没有关系。具体讲,它(Cloneable接口)没有指定clone方法,这个方法是从Object类继承的(应该是实现接口的类从Object类继承)。Cloneable接口的作用只是作为一个标记,指示 类设计者 了解克隆过程。对象对于克隆很“偏执”,如果一个对象请求克隆,但没有实现这个接口,就会生成一个受查异常(报错:java.lang.CloneNotSupportedException)。

    Cloneable接口是Java提供的一组标记接口(tagging interface)之一。有些程序员也称之为记号接口(marker interface)。注意:Comparable等接口的通常用途是确保一个类实现一个或一组特定的方法。标记接口不包含任何方法,它唯一的作用就是允许在类型查询中使用instanceof:

    if (obj instanceof Cloneable) ..

    建议自己程序中不要使用标记接口。

    即使clone的默认(浅拷贝)实现能够满足要求,还是需要实现Cloneable接口,将clone方法重新定义为public,再调用super.clone()。

    class Employee implements Cloneable()

    {

    // raise visibility level to public, change return type public Employee clone() throws CloneNotSupportedException

    {

    return (Employee) super.clone();

    }

    ...

    }

    如果一个类重写了clone方法,但是类没有声明实现接口 implements Cloneable,类会抛出一个CloneNotSupportedException异常。当然,Employee和Date类实现了Cloneable接口,所以不会抛出这个异常。不过编译器不会了解这一点,所以我们声明了这个异常:

    public Employee clone() throws CloneNotSupportedException

    这样,子类在不支持克隆时选择抛出一个CloneNotSupportedException异常。

    clone没有想象中的那么常用,标准库中只有5%的类实现了clone。

    展开全文
  • clone()方法是被protected修饰的受保护的方法,类只有实现了Cloneable接口,才可以在该类的实例上调用clone()方法,否则会抛出CloneNotSupportException异常。 Object的clone()方法创建并返回此对象的一个副本。...

    1. 克隆的用处

    在日常编码中我们经常需要产生某个对象的副本,这里的副本并不是指向同一个对象的不同引用,而是与当前对象状态一模一样的另一个新的对象。如果使用单纯的引用赋值,会发生什么效果呢?

    我们可以观察下面的代码:

    package com.coderap.foundation.clone;

    class Address {

    public String province;

    public String city;

    public Address(String province, String city) {

    this.province = province;

    this.city = city;

    }

    @Override

    public String toString() {

    return "Address{" +

    "province='" + province + '\'' +

    ", city='" + city + '\'' +

    '}';

    }

    }

    class Person {

    public String name;

    public Integer age;

    public Address address;

    public Person(String name, Integer age) {

    this.name = name;

    this.age = age;

    }

    }

    public class CloneTest {

    public static void main(String[] args) {

    Person person = new Person("Tom", 20);

    person.address = new Address("CA", "Los Angeles");

    System.out.println("before: " + person.name);

    System.out.println("before: " + person.age);

    System.out.println("before: " + person.address);

    Person newPerson = (Person) person;

    person.name = "Jack";

    person.age = 22;

    newPerson.address.province = "CA";

    newPerson.address.city = "Nevada";

    System.out.println("after: " + person.name);

    System.out.println("after: " + person.age);

    System.out.println("after: " + person.address);

    System.out.println("person equal newPerson ? " + person.equals(newPerson));

    }

    }

    在上面的代码中我们单纯地将一个新的引用指向一个已有的对象,然后使用新的引用对对象进行操作,可以发现,所有的更改在两个引用上都体现出来了:

    before: Tom

    before: 20

    before: Address{province='CA', city='Los Angeles'}

    after: Jack

    after: 22

    after: Address{province='CA', city='Nevada'}

    person equal newPerson ? true

    在Java中,两个引用同时指向相同的对象时,这两个引用是指向的同一块内存,所以使用任何一个引用对内存的操作都将直接反映到另一个引用上,单纯的引用赋值是不能够克隆对象的。为了解决克隆问题,Java提供了Cloneable接口和clone()方法。

    2. Cloneable 接口和 clone 方法

    Cloneable接口是一个标记接口,其中没有任何内容,定义如下:

    package java.lang;

    public interface Cloneable {}

    clone()方法是在Object类中定义的:

    protected native Object clone() throws CloneNotSupportedException;

    clone()方法是被protected修饰的受保护的方法,类只有实现了Cloneable接口,才可以在该类的实例上调用clone()方法,否则会抛出CloneNotSupportException异常。

    Object的clone()方法创建并返回此对象的一个副本。对于任何对象o,clone()方法有以下的规则:

    o.clone() != o为true;

    o.clone().getClass() == o.getClass()为true;

    o.clone().equals(o)一般情况下为true,但这并不是必须要满足的要求。

    Object中默认的实现是一个浅克隆,但是该方法是有缺陷的,如果需要实现深层次克隆的话,必须对类中可变域生成新的实例。

    2.1. 浅克隆

    浅克隆并不会把对象所有属性全部克隆一份,而是有选择性的克隆,克隆规则如下:

    基本类型。如果变量是基本类型,则克隆其值,比如int、float、long等。

    String字符串,对于字符串的克隆比较特殊,克隆的是引用地址,但是在修改的时候,它会从字符串池(String Pool)中重新生成新的字符串,原有的字符串对象保持不变,此处可以认为String是个基本类型。

    对象。如果变量时一个实例对象,则克隆地址引用,也就是说此时新克隆出的对象与原有对象共享该实例变量,不受访问权限的限制。这中克隆操作是非常危险的,意味着不同的对象之间对某些引用对象是共有的,相互修改将受到影响。

    注1:基本数据类型在克隆时是进行的原值克隆。

    如下面的代码,我们只是简单的在Person类中实现了Cloneable接口并且重写了clone()方法,同时进行克隆操作:

    package com.coderap.foundation.clone;

    class Address {

    public String province;

    public String city;

    public Address(String province, String city) {

    this.province = province;

    this.city = city;

    }

    @Override

    public String toString() {

    return "Address{" +

    "province='" + province + '\'' +

    ", city='" + city + '\'' +

    '}';

    }

    }

    class Person implements Cloneable {

    public String name;

    public Integer age;

    public Address address;

    public Person() {

    System.out.println("Person() execute");

    }

    public Person(String name, Integer age) {

    System.out.println("Person(String name, Integer age) execute");

    this.name = name;

    this.age = age;

    }

    @Override

    protected Object clone() throws CloneNotSupportedException {

    return super.clone();

    }

    }

    public class CloneTest {

    public static void main(String[] args) throws CloneNotSupportedException {

    Person person = new Person("Tom", 20);

    person.address = new Address("CA", "Los Angeles");

    System.out.println("before: " + person.name);

    System.out.println("before: " + person.age);

    System.out.println("before: " + person.address);

    Person newPerson = (Person)person.clone();

    newPerson.name = "Jack";

    newPerson.age = 22;

    newPerson.address.province = "CA";

    newPerson.address.city = "Nevada";

    System.out.println("after: " + person.name);

    System.out.println("after: " + person.age);

    System.out.println("after: " + person.address);

    System.out.println("person != newPerson ? " + String.valueOf(person != newPerson));

    System.out.println("person getClass equal newPerson getClass ? " + person.getClass().equals(newPerson.getClass()));

    System.out.println("person equal newPerson ? " + person.equals(newPerson));

    }

    }

    运行上面的代码,可以得到打印信息如下:

    Person(String name, Integer age) execute

    before: Tom

    before: 20

    before: Address{province='CA', city='Los Angeles'}

    after: Tom

    after: 20

    after: Address{province='CA', city='Nevada'}

    person != newPerson ? true

    person getClass equal newPerson getClass ? true

    person equal newPerson ? false

    我们可以得出以下结果:

    克隆一个对象不会重复调用对应类的构造方法;

    上述最后的三条的判断的结果是遵循了clone()方法三条规则的;

    基本类型和String类型的数据都是独立的,并不会收到新对象的影响,但是引用类型的对象会受到新对象的影响。

    需要注意的是,在修改城市信息时,如果我们直接指定newPerson.address = new Address("CA", "Nevada")其实是不会影响到原来的person对象的,因为虽然newPerson和person的address指向的同一个Address对象,但使用newPerson.address = new Address("CA", "Nevada")会给newPerson对象生成一个新的Address对象,并将newPerson的address引用指向这个新的对象,所以并不会影响到原有的person对象的address对象属性。

    Java中实现了Cloneable接口的类有很多,如ArrayList、Calendar、Date、HashMap、Hashtable、HashSet、LinkedList等等。我们在使用这些类时并不需要考虑浅克隆带来的影响。

    2.2. 深克隆

    深克隆操作应该将除自身对象以外的所有对象,包括自身所包含的所有对象实例都进行克隆。

    其实Object的clone()方法提供的是一种浅克隆的机制,如果想要实现对对象的深克隆,有两种办法:

    先对对象进行序列化,紧接着马上反序列化出;

    先调用super.clone()方法克隆出一个新对象来,然后在子类的clone()方法中手动给克隆出来的非基本数据类型(引用类型)赋值,比如ArrayList的clone()方法:

    /**

    * Returns a shallow copy of this ArrayList instance. (The

    * elements themselves are not copied.)

    *

    * @return a clone of this ArrayList instance

    */

    public Object clone() {

    try {

    ArrayList> v = (ArrayList>) super.clone();

    v.elementData = Arrays.copyOf(elementData, size);

    v.modCount = 0;

    return v;

    } catch (CloneNotSupportedException e) {

    // this shouldn't happen, since we are Cloneable

    throw new InternalError(e);

    }

    }

    展开全文
  • java的克隆分为深克隆和...3.最后,你要知道你为什么使用这个clone方法Cloneable接口作用:Object类中的clone()是protected的方法,在没有重写Object的clone()方法且没有实现Cloneable接口的实例上调用clone方法,...
  • Java8之Cloneable接口

    2021-02-28 10:34:39
    作用:实现对象的浅复制,在clone之后,改变其中一个对象的引用类型变量,会影响另外一个,改变不可变的属性,则不影响。查看源码package java.lang;public interface Cloneable {}测试public class Person ...
  • Cloneable接口

    2021-04-21 13:43:47
    Cloneable接口 1、Cloneable接口 Cloneable是一个接口,实现这个接口后,可以在类中重写Object中的clone方法,然后通过类调用clone方法进行克隆,如果不实现Cloneable接口,则会抛出CloneNotSupportedException异常...
  • 一、Cloneable接口 Cloneable只是一个标记接口,只有实现了这个接口,才能在类中重写clone方法,然后通过类调用clone完成功能实现,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常 1、...
  • 例如,在JavaAPI中,Integer、BigInteger、String以及Date类定义如下Cloneable接口Cloneable接口给出了一个可克隆的对象。若要出现需要创建一个对象拷贝的情况。为了这个目的,需要使用clone方法Cloneable定义如下:...
  • 实现 implements Cloneable接口,因为Object没有实现Cloneable接口 package com.hou.pojo; //object类本身并没有实现Cloneable这个接口,所以需要我们自己进行实现 public class User extends Object implements ...
  • 作用:允许实现了Cloneable接口的类的对象进行克隆操作。允许克隆的意思是可以调用clone()方法,至于是深拷贝还是浅拷贝,取决于如何重写Object的clone()方法。查看Cloneable接口的源码如下: package java.lang; ...
  • Cloneable接口是一个标记接口,也就是没有任何内容,定义如下:这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出...
  • jdk1.8中Cloneable接口的源码如下:/*Cloneable接口源代码,JDK1.8*/public interfaceCloneable {}我们会发现一件很有意思的事情,那就是Cloneable接口竟然没有定义任何的接口方法,这是为什么呢?Cloneable接口之...
  • 但是具体的复制方法实现还是在Object中,因此在覆写方法中只需要调用Object类中的clone()方法即可完成操作,而且在对象所在类中必须实现Cloneable接口才可以完成对象的复制操作。 浅拷贝:直接通过等号赋值的可变...
  • class Money implements Cloneable{ public double money = 12.8; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable{ ...
  • 不然无法序列化,报错 此块和Cloneable接口的不一样,(实现cloneable接口的此类,下面的类对象类,可以/可以不 实现cloneable接口) 4、遇自定义类皆实现Cloneable接口的深拷贝(前面2、说的是浅拷贝) 3、代码实现...
  • 1.Cloneable接口的使用 2.clone()方法的重写 3.关于clone()的使用 4.运行结果 5.验证clone()也为浅拷贝 6.关于浅拷贝的内存图解 7. 实现对象的深拷贝 (1)在本类中的拷贝方法中对引用类型进行拷贝 ...
  • java实现Cloneable接口克隆对象,javacloneable,下面实例展示如何一个类如下面实例展示如何一个类如何实现Cloneable接口,并展示如何克隆对象/** * Main.java * * @author byrx.net */public class Main { /** * ...
  • 不要问我,深拷贝与浅拷贝有什么区别?直接代码gif对比展示
  • 三、浅克隆 public class Student implements Cloneable { private String name; private int age; public Student() { super(); } public Student(String name, int age) { super(); this.name = name; this.age =...
  • 1、实现Cloneable接口表明该类的对象是允许克隆的。2、允许克隆的意思是:可以调用clone()方法。3、深拷贝还是浅拷贝,取决于如何重写Object的clone()方法。4、原对象和克隆对象的关系:深拷贝:阳关道和独木桥;浅...
  • 我的小记录首先语法上,搞清除,Java有个Cloneable接口,但这个接口是没有定义方法的。那实现了这个接口有什么用呢?再看Object类中,有个clone()方法,这个方法提供一个浅复制的功能,如果你的类不实现Cloneable...
  • Java技巧------Cloneable接口与clone方法描述Cloneable只起到一个描述标记的作用,这个接口没有定义任何方法或是包含其他内容。我们可以看一下源码定义。package java.lang;/*** @author unascribed* @see java.lang...
  • 今天看了一上午关于clone()和cloneable interface 的文章,我推荐一篇供大家参考学习。蓝色为我的翻译,有不当之处,大家多多包涵!clone() and the Cloneable Interface in Java......The clone( ) method ...
  • 先来看看JDK的解释:java.lang.CloneableA class implements the Cloneable interface to indicate to the java.lang.Object.clone() method that it is legal for that method to make a field-for-field copy of ...
  • 【这就是继承设计的巧妙之处了】 要想调用我们的clone()方法必须去实现Cloneable接口。 方法实现的浅拷贝 在我们上面的第二步的实现其实完全没有问题,你拷贝就完全拷贝过去,我们的copy对象就在堆内存重新划分到了...
  • 1、实现Cloneable接口,重写clone方法 Object默认的clone方法实际是对域的简单拷贝,对于简单数据类型,是值的拷贝; 对于复杂类型的字段,则是指针地址的拷贝,clone后的对象和原对象指向的还是一个地址空间。 所以...
  • /** * @Author 小浩 * @Date 2020/4/2 12:09 * @Version 1.0 **/ public class Person implements Serializable,Cloneable{ Phone phone; @Override protected Object clone() throws CloneNotSupportedException {...
  • 只有那些实现Cloneable接口的类能被复制。Cloneable接口没有定义成员。它通常用于指明被创建的一个允许对对象进行位复制(也就是对象副本)的类。如果试图用一个不支持Cloneable接口的类调用clone( )方法,将引发一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,726
精华内容 23,090
关键字:

cloneable接口的作用