继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

深入浅出| java中的clone方法

慕哥9229398
关注TA
已关注
手记 1282
粉丝 199
获赞 913

每天进步一丢丢,连接梦与想
我们还年轻,但这不是你浪费青春的理由

克隆和复制

clone,有人称之为克隆,有人称之为复制,其实都是同一个东西
本文称之为"克隆",毕竟人家方法名叫"clone"

为什要用克隆

想一想,为什么需要克隆?为什么不重新new一个?道理很简单,目的是想要两个相同的对象,重新new一个还得自己重新赋值,太麻烦

如何克隆一个对象?
如果是个初学者,可能会这么写

public class Student {
    String name;    public Student(String name) {        super();        this.name = name;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public static void main(String[] args){
        Student stu1 = new Student("小明");
        Student stu2 = stu1;
    }

}

这确实是做了克隆,但只是克隆了引用变量
来验证一下

 System.out.println("stu1:"+stu1.getName()+"  
      stu2:"+stu2.getName());
      System.out.println("stu1 == stu2 : "+(stu1 == stu2));      //改名字
      stu1.setName("小张");
      System.out.println("改名后 stu1:"+stu1.getName()+"  
      stu2:"+stu2.getName());//输出stu1:小明  stu2:小明
stu1 == stu2 : true改名后 stu1:小张  stu2:小张

修改了stu1的名字后,stu2的名字也随着改变
可以看出,两个引用stu1stu2指向同一个对象
如图

webp

image

你需要的是这样的克隆?
回想一下,平时真正需要的是两个不同对象

Object类中的clone

先来看下clone的源码,在Object类中

/*
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 x, the expression:
1) x.clone() != x will be true
2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
3) x.clone().equals(x) will be true, this is not an absolute requirement.
*/protected native Object clone() throws CloneNotSupportedException;

仔细看,它是个native方法,native方法是由非java语言实现的(因为java本身无法直接对操作底层进行访问和操作,需要通过其他语言实现)
注释主要说明了3点:

  1. 克隆对象和原对象不是同一个对象,占用不同的内存地址

  2. 克隆对象和原对象应该具有相同的类型,但它不是强制性的

  3. 克隆对象和原对象使用equals()方法比较应该是相等的,但它不是强制性的

因为每个类的基类都是Object,所以都有clone方法,但是它是protected,所以不能在类外访问
克隆一个对象,需要对clone重写

如何实现克隆

在说实现前,得区分下浅克隆和深克隆

  • 浅克隆:原对象和克隆对象不同,但对象内的成员引用相同

  • 深克隆:原对象和克隆对象不同,且对象内的成员引用也不同
    不同:不是同一个对象,所占内存地址不同
    成员引用:类中为引用类型的成员

以图说明,更形象些
男孩比喻为一个类,电脑比喻为类中的成员引用

webp

image

  • 一个男孩拥有一台电脑,通过浅克隆后,成了两个男孩,但他们共享一台电脑

  • 一个男孩拥有一台电脑,通过深克隆后,成了两个男孩,他们拥有各自的电脑

浅克隆

//学生类public class Student implements Cloneable{    private String name;    private Integer age;    private Bag bag;    public Student(String name,Integer age,Bag bag) {        this.name = name;        this.age = age;        this.bag = bag;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public Integer getAge() {        return age;
    }    public void setAge(Integer age) {        this.age = age;
    }    public Bag getBag() {        return bag;
    }     public void setBag(Bag bag) {        this.bag = bag;
    }    @Override
    public Student clone(){
        Student stu = null;        try{
            stu = (Student)super.clone();
        } catch (CloneNotSupportedException e){
            e.printStackTrace();
        }        return stu;
    }    @Override
    public String toString() {        return "Student{" +                "name='" + name + '\'' +                ", age=" + age +                ", bag=" + bag.getName() +                '}';
    }
}
//背包类public class Bag {
    private String name;    public Bag(String name) {        this.name = name;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }
}
//测试类public class Test {    public static void main(String[] args){
        Student stu1 = new Student("小明",25,new Bag("小明的背包"));
        Student stu2 = stu1.clone();
        System.out.println("两对象是否相等");
        System.out.println("stu1 == stu2 "+(stu1 == stu2));
        System.out.println("stu1 "+stu1.toString());
        System.out.println("stu2 "+stu2.toString());
        System.out.println("对象内引用成员是否相等");
        System.out.println("stu1.name ==  stu2.name "+ (stu1.getName() ==  stu2.getName()));
        System.out.println("stu1.age ==  stu2.age "+(stu1.getAge() ==  stu2.getAge()));
        System.out.println("stu1.bag ==  stu2.bag "+(stu1.getBag() ==  stu2.getBag()));
    }
}//输出两对象是否是同一对象
stu1 == stu2 falsestu1 Student{name='小明', age=25, bag=小明的背包}
stu2 Student{name='小明', age=25, bag=小明的背包}
对象内引用成员是否相等
stu1.name ==  stu2.name truestu1.age ==  stu2.age truestu1.bag ==  stu2.bag true

可看出,原对象和克隆对象不是同一对象,克隆对象内的值与原对象相同;对象内引用成员相等,说明只做了引用克隆,不同引用指向同一对象

//改变stu1类中成员的值stu1.setName("小张");
stu1.setAge(18);
stu1.getBag().setName("小张的背包");
System.out.println("stu1 "+stu1.toString());
System.out.println("stu2 "+stu2.toString());//输出stu1 Student{name='小张', age=18, bag=小张的背包}
stu2 Student{name='小明', age=25, bag=小张的背包}



作者:java从心
链接:https://www.jianshu.com/p/a820d0124bda


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP