簡體   English   中英

super.clone()操作在派生類中不起作用

[英]super.clone() operation not works in Derived Class

之所以提出這個問題,是因為我的項目面臨技術難題。

問題:我需要克隆一個類的對象,在該對象中它擴展了第三方庫類的屬性(繼承)(在該類中,我們無權修改其內容)

讓我用下面的例子解釋:

家長班:

public class UnChangeableBaseClass {

  //fields and Methods

}

兒童班:

class DerivedLocalClass extends UnChangeableBaseClass implements Cloneable {

   // local fields and methods


   public Object clone(){

      Object clonedObj= null;

      try{
       clonedObj = super.clone();
      }
      catch(CloneNotSupportedException e){
        //log exceptions
      }

   }

}

當我嘗試執行此操作時, super.clone()方法引用的是Class- UnChangeableBaseClass Type,並且它不會覆蓋Object clone()方法。 我相信所有類都使用java.lang.Object class類進行了擴展, protected Object clone()隱式protected Object clone()方法將繼承到此Parent類。 因此,我以這種方式認為派生類中的此方法將覆蓋“父/對象”克隆方法。 但是在運行時JVM中,搜索在UnChangeableBaseClass顯式定義的克隆方法。 希望我以正確的方式進行解釋,不要讓您感到困惑。

我的問題如下:

  1. 在這種無法添加任何方法的典型情況下,如何實現克隆方法
    在父類中具有super.clone()來調用對象克隆方法。

  2. 如果以上情況是不可能的,是否有其他方法可以克隆派生類
    對象(考慮上述情況下的所有限制)

  3. 最后,僅要了解這種JVM行為的原因(如上所述)。

在這種典型情況下,我們如何實現克隆方法,在這種情況下,我們不能在父類中添加任何方法來讓super.clone()調用對象克隆方法。

好吧,由於clone方法是Object類中的一種受保護方法,因此,由於clone方法是從Object類擴展的,因此在超級類UnChangeableBaseClass也可以訪問它。 因此,基本上,您可以使用super.clone()從基類DerivedLocalClass訪問clone方法。

如果以上情況不可能,是否有其他方法克隆派生類對象(通過考慮上述情況中的所有限制)

我建議,即使您可以選擇使用clone方法來克隆對象,也不應使用它。 最好在派生類中使用copy-constructor ,然后向基類構造函數中添加一個super()調用。

另請參閱Effective Java - Item#11 - Override clone judiciously ,這表明clone方法已損壞。

在本文中: Josh Bloch on Design - Copy Constructor versus Cloning ,您希望看到Bloch第一段:-

如果您已經閱讀了我書中有關克隆的內容,尤其是您在兩行之間閱讀的話,您會知道我認為克隆已被嚴重打破。 存在一些設計缺陷,其中最大的缺陷是Cloneable接口沒有克隆方法。 這意味着它根本行不通:制作可克隆內容並不能說明您可以使用它做什么。 相反,它說明了其內部功能。 它說,如果通過重復調用super.clone最終導致調用Object的clone方法,則此方法將返回原始字段的副本。

因此,結論是,您可以在DerivedLocalClass擁有一個copy constructor ,該copy constructor將向您返回調用對象的副本,如下所示:-

public DerivedLocalClass(DerivedLocalClass obj) {
    this.setVar(obj.getVar());
}

JVM克隆通過使用Marker接口Cloneable而不是尋找Object.clone()來工作。 的確,所有Java類都將繼承clone方法,但是根據javadoc的說法,它是Cloneable的

A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class.

在您的情況下,您不能執行super.clone(),因為它沒有被標記為可克隆。 如果您不能更改父類,則必須自己復制它。

我正在使用Java 1.7,在運行OP給定的代碼時沒有任何問題。 除非超類具有重寫的克隆以引發異常,否則我認為即使超類未聲明自身可克隆,此方法也應起作用。

我會注意到

public Object clone()

沒有覆蓋clone方法,它缺少throws子句。

正確的方法簽名如下

@Override
public Object clone() throws CloneNotSupportedException {
    return super.clone();
}

Clone是Object類中的Protected方法,因此您可以在類內部以及從其進行擴展時訪問。 super.clone()僅需要從對象上調用clone()方法,該對象在當前類對象上this方法調用internalClone

   internalClone((Cloneable) this);

因此,如果調用Object實例不是Cloneable ,則Object內部的上面clone()方法只會拋出CloneNotSupportedException

我看到一些關於克隆方法的誤解

  1. clone()方法在Object類內部protected因此您不能在類外部調用clone() 例如child.clone()除非您覆蓋它並public訪問
  2. Cloneable是標記接口,如果不標記Cloneable類,則調用clone()方法將得到CloneNotSupportedException
  3. 如果一個類僅包含基本字段或對不可變對象的引用,則通常情況是無需修改super.clone返回的對象中的任何字段。
  4. 按照慣例,應通過調用super.clone獲得返回的對象。 如果一個類及其所有superclasses (except Object)遵守此約定,則x.clone().getClass() == x.getClass()

所以下面的代碼可以正常工作

public  class Child extends UnChangeableBaseClass
        implements
            Cloneable {

    int index = 0;

    public Child(int index) {

        this.index = 10;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

參考文獻:

  1. 對象#克隆()
  2. 可復制

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM