Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java 8中Cloneable中没有默认的clone()_Java_Java 8_Clone_Cloneable_Default Method - Fatal编程技术网

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

为什么Java 8中Cloneable中没有默认的clone(),java,java-8,clone,cloneable,default-method,Java,Java 8,Clone,Cloneable,Default Method,Java中的Cloneable本质上是不可靠的。具体地说,我对接口的最大问题是,它需要一个不定义方法本身的方法行为。因此,如果遍历一个Cloneable列表,您必须使用反射来访问它定义的行为。然而,在Java8中,我们现在有了默认方法,现在我问为什么在Cloneable中没有默认的clone()方法 然而,我理解为什么这是一个明确的设计决策,因此可以做出例外 我有点想象不推荐Object.clone(),并将其内部代码更改为如下内容: if(this instanceof Cloneable)

Java中的
Cloneable
本质上是不可靠的。具体地说,我对接口的最大问题是,它需要一个不定义方法本身的方法行为。因此,如果遍历一个
Cloneable
列表,您必须使用反射来访问它定义的行为。然而,在Java8中,我们现在有了默认方法,现在我问为什么在
Cloneable
中没有默认的
clone()
方法

然而,我理解为什么这是一个明确的设计决策,因此可以做出例外

我有点想象不推荐
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()
  • 更不用说这将解决
    Cloneable
    所面临的巨大问题。虽然它很乏味,而且很容易错误地实现,但它将解决一个巨大的面向对象接口问题

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


    这是否已经在内部讨论过,但从未取得成果?若然,原因为何?如果是因为接口不能默认对象方法的原因,那么在这种情况下做一个例外是否有意义,因为所有继承
    Cloneable
    的对象都需要
    clone()

    您的问题有点宽泛,而且更具讨论性,但我可以解释一下这一点

    用有效的Java语言™, 约书亚·布洛赫(Joshua Bloch)提供了有关情况的详细情况。他一开始就带着一点历史背景
    Cloneable

    Cloneable接口旨在作为对象的mixin接口 宣传他们允许克隆。不幸的是,它未能达到这一目的。它的主要缺陷是缺少克隆方法,并且对象的克隆方法受到保护。如果不诉诸反射,就不能仅仅因为对象实现了Cloneable而对其调用clone方法

    并继续进行推理

    [Cloneable]确定对象的受保护克隆实现的行为:如果类实现了Cloneable,则对象的clone方法返回对象的逐字段副本。。。这是对接口的一种非常非典型的使用,不需要进行仿真。通常,实现接口说明类可以为其客户机做些什么。在可克隆的情况下,它修改超类上受保护方法的行为

    如果实现可克隆接口对类有任何影响 类及其所有超类必须遵守一个相当复杂、不可执行且 稀薄记录的协议。由此产生的机制是语言外的:它创建一个对象而不调用构造函数

    这方面有很多细节,但只需注意一个问题:

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


    我认为这足以说明为什么不在接口中使用
    default
    方法进行克隆。正确地实现它将非常复杂。

    我的经验可能远不是主流,但我使用
    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()
    ,但不希望公开它。相反,您提供了另一种方法,允许使用其他名称进行克隆。因此,在
    Cloneable
    中使用public
    clone()
    将不必要地污染类的公共接口

    我使用
    Cloneable
    的另一个例子是
    Spliterator.trySplit()
    的实现。请参阅返回给定数量常量对象的简单拆分器的说明。它有四个专门化(对象、整数、长整数和双精度),但这要归功于<