【问题标题】:How to clone an Object you dont know the type of?如何克隆一个你不知道类型的对象?
【发布时间】:2011-04-01 02:10:44
【问题描述】:

这里更容易用代码解释

Object anObj;
anObj = new MyObj();
anObj = new Rectangle();
anObj.clone();//this doesnt exist because its on the root Object class

在这个例子中我可以用什么来代替 Object.clone() 方法?

----------- 额外信息 ---------- --------

我已经添加了额外的信息,但它似乎已经出现在所有答案的中间,所以它再次出现,以便阅读。

您好,所有这些都对克隆或复制主题非常有帮助,我现在需要考虑一下。但他们对最初的问题没有帮助。也许我提供的更多信息将帮助您了解我所追求的。

我正在覆盖我的每个对象的克隆,并添加完全克隆对象所需的所有其他克隆和复制方法,这包括添加自定义方法来复制缓冲图像。 即:-

public Object clone() {//i copied from 'thelost's answer
    try { 
        CloningExample copy = (CloningExample)super.clone(); 
        copy.names = (LinkedList)names.clone(); 
        return copy; 
    } catch (CloneNotSupportedException e) { 
        return null; 
    } 
}

但是我的类中有一个变量是 Object,但是因为它包含不同类型的各种其他对象,所以我的每个类型都有一个 clone 方法,但是没有检查它是否是我的每个类型然后调用 clone () 在我的类型上,这将很长,因为我有很多类型,我看不到如何轻松复制或克隆对象。有没有办法让我只写一个这样的静态方法?

static findTypeAndCopy(Object thisobj){ 
    if(thisobj==null) 
        return null;

    if(thisobj instanceOf MyObj1){ 
        return ((MyObj1)thisobj).clone(); 
    }else if(thisobj instanceOf MyObj2){ 
        return ((MyObj2)thisobj).clone(); 
    ... 
    etc
}

???

【问题讨论】:

  • Cloneable 坏了。考虑看大局,看看为什么需要这样做,如果你真的需要这样做。

标签: java object cloning


【解决方案1】:

您可以检查它是否实现了Cloneable 接口,如果实现了则使用克隆方法。

here 是关于如何自己实现它的示例。

【讨论】:

    【解决方案2】:

    正如其他人所说:Clonable 已损坏,您应该考虑其他选项,例如复制构造函数。话虽如此,如果你真的必须使用 clone(),这里有一个应该可以工作的解决方案:

    Object clone = null;
    if(anObj instanceof Clonable) {
        Method cloneMethod = anObj.getClass().getMethod("clone");
        /*
         * TODO: Handle the case where an object is cloneable but 
         * does not have a public clone() method.
         */
        clone = cloneMethod.invoke(anObj);
    } else {
        throw new RuntimeException("can't clone object");
    }
    

    或者你可以使用反射逐个字段克隆对象,如果它没有实现clone()...获取所有字段,将值复制到新对象。但这很棘手,如果对象没有无参数构造函数。

    【讨论】:

    • 这行不通。 Cloneable 接口没有方法clone
    • @Tadeusz Kopec 你是对的,用应该可行的解决方案更新了答案。
    【解决方案3】:

    您无法确定一个类是否具有克隆能力,因为clone() 是 Object 的一个方法。您可以做的最好的事情是检查课程是否为Cloneable。通常当一个类是Cloneable 时,意味着开发者覆盖了clone() 方法。

    但即便如此,Object 也无法调用此方法。

    有反射解决方案。但正如文档所说:

    即使反射调用 clone 方法,也不能保证它会成功。

    您可以阅读文档herethere 是 Josh Bloch 对此类的声明(最后一段)。

    【讨论】:

    • 你是如何让编译器接受受保护方法的调用的?
    • 你不能。当您实现 Cloneable 时,您必须使用公共修饰符,以便每个人都可以使用它。
    • 那行不通! Cloneable 坏了。
    • HEBERT 不,根据文档,您“应该”。即使该方法在您的类上是公共的:变量是 Object 类型,因此该方法是受保护的。您需要使用反射来获取方法引用并调用它。
    • @polygenelubricants,@Thomas 你是对的。我忘记了那部分。我会编辑答案。
    【解决方案4】:

    最好的办法是避免克隆,因为it is broken.
    Cloneable 接口没有方法clone。方法cloneObject 类中定义为protected。所以要调用clone,您需要知道可以访问clone 的对象类型。 更好的主意是复制构造函数(如 Bloch 建议的那样)或序列化和反序列化(例如通过 XML)。
    也许您可以通过反射访问clone,但我不确定。我不鼓励它。

    【讨论】:

    • 我同意克隆被破坏,但使​​用反射来工作是一个坏主意。
    • @Chris 我同意这是个坏主意。但是如果 f1wade 想在不知道对象类型的情况下调用它,这是唯一的可能性。
    • @Chris - 最好说 Cloneable 坏了。您仍然应该使用 clone() 来复制数组(例如)。
    【解决方案5】:

    您似乎已经意识到 Java 中的 Cloneable 已损坏。

    以下是来自Effective Java 2nd Edition的作者an interview with Josh Bloch的一些引用:

    如果你读过我书中关于克隆的内容,特别是如果你读到字里行间,你就会知道我认为clone 被严重破坏了。有一些设计缺陷,其中最大的一个是Cloneable 接口没有clone 方法。这意味着它根本不起作用:制作Cloneable 并没有说明您可以用它做什么。相反,它说明了它可以在内部做什么。它表示如果通过重复调用super.clone 最终调用Objectclone 方法,该方法将返回原始的字段副本。

    但它没有说明你可以用实现Cloneable 接口的对象做什么,这意味着你不能进行多态clone 操作。

    以下是书中的一些引述,第 11 项:明智地覆盖 clone

    [...] 你最好提供对象复制的替代方法,或者干脆不提供该功能。

    [...] 一个很好的对象复制方法是提供复制构造函数复制工厂。复制构造函数只是一个构造函数,它接受一个参数,其类型是包含构造函数的类:

    public Yum(Yum yum);
    

    复制工厂是复制构造函数的static工厂模拟:

    public static Yum newInstance(Yum yum);
    

    相关问题


    替代方案:Cloneable2.0

    如果你真的坚持要有一个不被破坏的类似Cloneable 的功能,你可以写这样的东西(为额外的爵士乐而生成):

    public class DupableExample {
    
        interface Dupable<T> {
            T dup();
        }   
        static class Sheep implements Dupable<Sheep> {
            Sheep(Sheep sheep) { }
            @Override public Sheep dup() {
                return new Sheep(this);
            }
        }
        public static void main(String[] args) {
            Dupable<?> dupable = new Sheep(null);
            System.out.println(dupable);
            System.out.println(dupable.dup());
            
            // no cast needed
            Sheep dolly2 = new Sheep(null).dup();
        }
    }
    

    输出应该是这样的(as seen on ideone.com):

    DupableExample$Sheep@{some hexadecimal code}
    DupableExample$Sheep@{a different hexadecimal code, in all likelyhood}
    

    所以现在给定任何Dupable&lt;T&gt;,您可以在其上调用T dup() 以获得您期望的副本。

    这只是一个概念验证:在实际实现中,您的复制构造函数/复制工厂/任何复制机制实际上都会实现复制逻辑,Dupable&lt;T&gt; 将是 public 顶级 @987654349 @。

    【讨论】:

    • 也许我没听懂你的答案...但是你如何真正克隆 Object 类型的东西?
    【解决方案6】:
    interface PublicCloneable extends Cloneable{
        public Object clone();
    }
    
    class MyObject implements PublicCloneable {
        public Object clone() {
            return super.clone();
        }
    }
    
    class MainObject {
        public static void main(String[] params) {
            Object m = new MyObject();
    
            if (m instanceof PublicCloneable) {
                Object c = m.clone();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-19
      • 2011-07-26
      • 1970-01-01
      • 2012-05-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多