十月读书笔记:Effective Java(五)--clone和toString方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/l00149133/article/details/52947509

一. 关于toString方法
作为一个应用程序开发者,而非一个”api开发者”,我们其实并不需要像作者一样关注过多的东西,比如toString是否需要一个明确的注释等。
需要记住的是:
1. 如果是一个value类,比如bigInteger,或者我们自己写的Student等,最好重写它的toString方法,用来展示一些类的信息,比如一个Student类,它的toString方法可能会返回学生id+姓名这样的信息,以便于调试。
2. 如果你没有重写toString方法,那类返回的是:类名+@ +对象的hash值,比如Student@127d82

二. 关于clone方法
作为java程序员都很熟悉这个办法,它用来创建一个对象的copy,这个copy有着不同的地址,但是跟被copy的对象内容相同。
如何使用clone方法?
你会发现clone方法是protected的。使用它,你需要先让你的类实现一个接口Cloneable。如果你不实现这个接口,而是直接用clone方法,会给你抛出一个异常:CloneNotSupportedException。。。
所以说,Cloneable这个接口设计得很奇葩,绝大多数情况下,接口是为了告诉用户,它可以实现什么,但是Cloneable这个接口里面,是空的。。。它存在的意义,在于改变实现这个接口的类的父类的clone方法的行为(不实现,就抛出异常,实现了,才给你返回值,我擦。。。)
什么情况下会用到clone?比如我们想给其他程序员提供一个对象,但是我们又不想这个对象被修改,那我们可以提供这个对象的clone方法。
但是作者不建议开发者使用和重写这个方法,除非你真的想低消耗的copy一个对象,原因是clone是一个危险操作,它可能产生你预料之外的结果。
例如,如果你的对象里包含了一个引用,比如另外一个对象。那你的clone方法copy的对象里,也将指向这个引用,这样你的副本就可以操作这个对象的引用了,而这不是我们所预想的结果。比如下面这个例子:

public class Student implements Cloneable{
    public int id;
    public School school;

    public Student clone(){
        try {
           Student result = (Student) super.clone();
           return result;
       } catch (CloneNotSupportedException e) {
           throw new AssertionError();
       }
    }
}

你可以看到,我们调用了Student的父类的clone方法。
这里会存在两个问题:
1. 我可以保证我自己的Student类的clone方法是没有问题的,但是我并不能保证所有的父类都是OK的,比如Student不是继承自Object,而是另外一个类Person,那我们并不知道Person类的clone方法是不是正确的
2. 另外,我们虽然clone了Student的对象,但是我们对于Student里面的School对象并没有处理,其实你clone的这个副本里,School对象跟原本的对象里的School指向同一个地址。而这样会导致什么呢:

Student s1 = new Student();
s1.id = 1;
s1.school = new School();

Student s2 = s1.clone();
System.out.println(s1 == s2); //false, 因为clone的对象跟原对象地址不同
System.out.println(s1.school == s2.school);  //true!!因为你没有clone School对象,所以s1和s2的school指向了同一个地址。

这样我们的本意是clone一个对象,不让开发者的操作影响到我们原本的对象,显然这样是失败的

如何解决这个问题?把里面的引用都实现clone一遍。。。
类似这样:

    public Student clone(){
        try {
           Student result = (Student) super.clone();
           result.school = result.school.clone();
           return result;
       } catch (CloneNotSupportedException e) {
           throw new AssertionError();
       }
    }

有没有更高级的方法? 我网上查了下,貌似利用Serializable接口可以实现,但是并没有深研究。
总之,建议大家不要随意使用clone方法

猜你喜欢

转载自blog.csdn.net/l00149133/article/details/52947509