当前位置:  开发笔记 > 编程语言 > 正文

为什么Java 8中的Cloneable中没有默认的clone()

如何解决《为什么Java8中的Cloneable中没有默认的clone()》经验,为你挑选了2个好方法。

Cloneable在Java中本质上是破碎的.具体来说,我对界面的最大问题是它需要一种不定义方法本身的方法行为.因此,如果遍历Cloneable列表,则必须使用反射来访问其定义的行为.但是,在Java 8中,我们现在有默认方法,现在我问为什么没有默认clone()方法Cloneable.

我理解为什么接口不能默认Object方法,但是,这是一个明确的设计决策,因此可以做出异常.

我有点想到弃用Object.clone()并将其内部代码更改为:

if(this instanceof Cloneable) {
    return ((Cloneable) this).clone();
}
else {
    throw new CloneNotSupportedException();
}

并继续前进任何魔法使其clone()成为默认方法Cloneable.这并没有真正解决,clone()仍然可以很容易地错误地实现,但这本身就是另一个讨论.

据我所知,这种变化将完全向后兼容:

    当前覆盖clone()但未实现的类Cloneable(为什么?!)在技术上仍然可以(即使在功能上不可能,但这与以前没有什么不同).

    当前覆盖clone()但实现的类Cloneable在其实现上仍将起相同的作用.

    当前没有覆盖clone(),但确实实现Cloneable(为什么?!)的类现在将遵循规范,即使它在功能上并不完全正确.

    使用反射并提到的那些Object.clone()仍然可以在功能上工作.

    super.clone()即使它正在引用,它在功能上仍然是相同的Object.clone().

更不用说这将解决一个巨大的问题Cloneable.虽然繁琐且仍然容易错误地实现,但它将解决界面的巨大面向对象问题.

我能看到的唯一问题是那些实现Cloneable没有义务覆盖的问题clone(),但这与以前没有什么不同.

这已在内部进行过讨论,但从未取得成果吗?如果是这样,为什么?如果是因为接口不能默认使用Object方法,那么在这种情况下做出异常是否有意义,因为所有继承Cloneable的对象都是期待clone()的?



1> user1803551..:

你的问题有点广泛而且更多的讨论,但我可以对这个问题有所了解.

Effective Java™中,Joshua Bloch给出了相应的情况.他打开了一段历史Cloneable

Cloneable接口旨在作为对象的mixin接口,以宣传它们允许克隆.不幸的是,它没有达到这个目的.它的主要缺陷是缺少克隆方法,而Object的克隆方法受到保护.如果不依靠反射,就不能仅仅因为它实现Cloneable而在对象上调用clone方法.

并继续推理

[Cloneable]确定Object的受保护克隆实现的行为:如果一个类实现Cloneable,则Object的clone方法返回该对象的逐个字段副本......这是一个非常非典型的接口使用,而不是一个被模拟的接口.通常,实现接口会说明类可以为其客户做些什么.在Cloneable的情况下,它修改了超类上受保护方法的行为.

如果实现Cloneable接口对类有任何影响,则该类及其所有超类必须遵守相当复杂,不可执行且记录细则的协议.结果机制是extralinguistic:它创建一个对象而不调用构造函数.

这里有很多细节,但要注意一个问题:

克隆体系结构与引用可变对象的最终字段的正常使用不兼容.

我认为这足以说明default在接口中有一个方法进行克隆.正确实施它会非常复杂.



2> Tagir Valeev..:

我的经验可能远不是主流,但我使用clone()并支持当前的设计Cloneable.可能最好将它作为注释,但Cloneable在注释之前出现很久.我的观点是,这Cloneable是一个低级别的事情,没有人应该做类似的事情obj instanceof Cloneable.如果您Cloneable在某些业务逻辑中使用,那么声明自己的接口或抽象类会更好,这些接口或抽象类公开clone()给公共并在所有业务逻辑对象中实现它.有时您可能不希望clone()实际暴露,但创建自己的clone()内部使用方法.

例如,假设您具有命名对象的层次结构,其中名称在构造后无法更改,但您希望允许使用新名称克隆它们.您可以创建一些这样的抽象类:

public abstract class NamedObject implements Cloneable {
    private String name;

    protected NamedObject(String name) {
        this.name = name;
    }

    public final String getName() {
        return name;
    }

    public NamedObject clone(String newName) {
        try {
            NamedObject clone = (NamedObject)super.clone();
            clone.name = newName;
            return clone;
        }
        catch(CloneNotSupportedException ex) {
            throw new AssertionError();
        }
    }
}

即使您实现了Cloneable,也希望使用clone(),但不想公开公开它.相反,您提供了另一种允许使用其他名称克隆的方法.因此,公开clone()进入Cloneable将不必要地污染您的类的公共接口.

我使用的另一种情况Cloneable是执行Spliterator.trySplit().查看简单spliterator 的实现,它返回给定数量的常量对象.它有四个特化(对象,整数,长整数和双精度),但多亏了clone()trySplit()只能在超类中实现一次.再一次,我不想暴露clone(),我只是想自己使用它.

总而言之,clone()Cloneable界面中没有方法实际上更灵活,因为它允许我决定是否要公开它.

推荐阅读
手机用户2402852387
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有