Cloneable实现对象克隆

在其他文章中已经说明了场景,和一些对象克隆的实现方式。本篇文章主要是对Cloneable接口如何实现对象克隆展开。

首先需要声明下,对象有分为浅克隆和深克隆。

浅克隆

浅克隆是对要克隆的对象,其中的基本类型复制一份新的产生给对象。但是对于非基本类型的数据类型,仅仅是复制一份引用给新产生的对象。即基本类型是新产生的,非基本类型是复制一份内存引用。

实现步骤:

1.实现Cloneable接口

要clone方法,为什么还要实现Cloneable接口呢?我们可以看看,Cloneable其中是一个空方法,他个RandomAccess一样

都属于,标识接口。针对的是Object里的clone方法,进行重写。告诉Object而已。如果调用了super.clone()方法。没有实现Cloneable接口。那么会抛出异常CloneNotSupportedException异常。

2.重写clone方法。

JDK中的API文档也说明了,这是一个对象拷贝的过程,不是对象的初始化过程。他包含了一些原有对象的信息。

Object中的clone的返回值是native。native属于一般是由C语言实现,效率一般都高于java代码,所以这里我们没有选择new一个新的对象,而是选择对象拷贝。

Object中的clone修饰符是protected,我们要把它改成public。

 实例代码如下:

bean:school,student。school中包含有student。main为执行方法。

student类如下:

package run;

public class student {
    private String gg;

    public String getGgg() {
        return gg;
    }

    public void setGgg(String ggg) {
        this.gg = ggg;
    }
    

    @Override
    public String toString() {
        return "student{" +
                "gg='" + gg + '\'' +
                '}';
    }


}

school类代码如下:

package run;

public class school implements Cloneable{
    private String name;
    private String age;
    private student st;

    public student getSt() {
        return st;
    }
    public void setSt(student st) {
        this.st = st;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

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

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

main的执行方法:

package run;

public class main {

        public static void main(String args[]) throws CloneNotSupportedException {
                student b1 = new student();
                b1.setGgg("123");

                school school1 = new school();
                school1.setAge("11");
                school1.setName("lsp");
                school1.setSt(b1);

                school school2 = (school) school1.clone();
                school2.setAge("26");
               school2.getSt().setGgg("456");

                System.out.println(school1);
                System.out.println(school2);
        }


}

输出如下:

school{name='lsp', age='11', st=student{gg='456'}}
school{name='lsp', age='26', st=student{gg='456'}}

分析:通过输出可以看出,浅克隆对于基本类型数据,已经完成了克隆,但是对于非基本类型数据还是指向同一个内存地址。

 

深克隆

深度克隆,其实就是对于浅度克隆的一种完善,浅度克隆只能完成基本类型的克隆,对于非基本类型无法克隆,只能复制内存地址到新的对象上。而深度克隆不同,深度克隆是完成了,基本数据类型和非基本数据类型,都可以克隆。

深度克隆:

要克隆的类和类中所有非基本类型对应的类

1.都要实现java.lang.Cloneable接口。

2.都要重写java.lang.Object.clone()方法。

3.在主类上添加子类的Clone方法。

 

 实例代码如下:

bean:school,student。school中包含有student。main为执行方法。

 

student类和浅克隆的区别在于,实现了Cloneable接口。重写了clone方法。

package run;

public class student implements Cloneable{
    private String gg;

    public String getGgg() {
        return gg;
    }

    public void setGgg(String ggg) {
        this.gg = ggg;
    }

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

    @Override
    public String toString() {
        return "student{" +
                "gg='" + gg + '\'' +
                '}';
    }


}

 

school类的clone方法是重点,它调用了子类的clone方法。所以才可以实现深度克隆。

package run;

public class school implements Cloneable{
    private String name;
    private String age;
    private student st;

    public student getSt() {
        return st;
    }
    public void setSt(student st) {
        this.st = st;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    @Override
    protected school clone() throws CloneNotSupportedException {
        school s = (school) super.clone();
        s.st= (student) st.clone();
        return s;
    }

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

 

main方法执行没有改动:

package run;

public class main {

        public static void main(String args[]) throws CloneNotSupportedException {
                student b1 = new student();
                b1.setGgg("123");

                school school1 = new school();
                school1.setAge("11");
                school1.setName("lsp");
                school1.setSt(b1);

                school school2 = (school) school1.clone();
                school2.setAge("26");
               school2.getSt().setGgg("456");

                System.out.println(school1);
                System.out.println(school2);
        }


}

输出如下:

school{name='lsp', age='11', st=student{gg='123'}}
school{name='lsp', age='26', st=student{gg='456'}}

分析:通过上述代码输出,可以看到引用数据类型,互不影响了。

 


补充:

1.重写,重写的返回值可以是原返回值,或者原返回值类型的子类。

2.java的基本类型,byte,short,int,long,char,float,double,boolean。但是非基本类型比如,integer,stringbuffere。这些非基本数据类型的对象。让他们实现Cloneable并重写clone非常的麻烦。所以大多数情况下,程序员还是会选择使用序列化的方式,完成对象克隆。

3.另外clone的写法。

默认生成如下:

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

优化生成:

    @Override
    protected Object clone()   {
        try {
            return (student)super.clone();

        }catch (CloneNotSupportedException e){
            return null;
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值