簡體   English   中英

為什么不能克隆java.lang.Object?

[英]Why java.lang.Object can not be cloned?

當我嘗試克隆一個通用對象時,出現編譯時錯誤。 為什么?

    Object obj=new Object();
    obj.clone();  // Here compile time error "The method clone() from the type Object is not visible"

每個類都擴展了Object類,克隆方法在Object類中受到保護。

protected的方法可以在同一個包中訪問,也可以通過subclasses訪問,所有類都是java.lang.Object的子類。

因為cloneObject類中是受保護的。 這不是public的。

訪問對象的clone()方法的唯一方法是知道它有一個具有公共clone()方法的編譯時類型。

這將是讓克隆工作的最低限度:

public class SubObj implements Cloneable {
  public Object clone() { return super.clone(); }
}

根據Java SE 文檔

Object 類本身並沒有實現 Cloneable 接口,因此在類為 Object 的對象上調用 clone 方法將導致在運行時拋出異常。

protected的字段只能從同一個包內部訪問,因此只能從位於java.lang包中的任何類訪問Object類的clone()方法。

您必須顯式實現 Cloneable 接口。 請參閱此線程,其中給出了解釋。

如果你使用 Groovy 這樣你就可以繞過 java 編譯錯誤,你會得到這個:

Exception in thread "main" java.lang.CloneNotSupportedException: java.lang.Object
    at java.lang.Object.clone(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
    at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:766)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:754)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:198)
    at regexTests.main(regexTests.groovy:19)
ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2
JDWP exit error AGENT_ERROR_NO_JNI_ENV(183):  [../../../src/share/back/util.c:820]

如果您閱讀克隆 API(我將鏈接它),它會說如果未實現接口,則調用 *.clone() 將拋出CloneNotSupportedException

鏈接到java.lang.Object的克隆 API http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#clone%28%29

[編輯] Original Question™ 問了為什么這個方法以它現在的方式可見。 這是因為它只能由 java.lang 包中的方法訪問。 它不是為了讓程序員能夠克隆Object 如果您不想克隆您的 OWN 對象,那么拋出CloneNotSupportedException正是您想要做的。

 void method() {

    Object obj=new Object(); //Object is a parent class, it's not inherit from any other class...     
    obj.clone();        //  compile time error   

}

我們無法從不同的包訪問“Has A”關系的受保護方法,因為您的類包是 (com.xxx.yyy) 和對象類包是 (java.lang) 這兩個類在不同的包中。

受保護的方法可以在同一個包中訪問,也可以通過子類訪問(是一種關系)

我試過這段代碼:

public final class User {


    private String name;
    private boolean isActive;
    private String userId;
    private Address address;


    // can be constructed using this constructor ONLY !
    public User(String name, boolean isActive, String userId, Address address) {
        this.name = name;
        this.isActive = isActive;
        this.userId = userId;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public boolean isActive() {
        return isActive;
    }

    public String getUserId() {
        return userId;
    }

    public Address getAddress() {
        return address;
    }

    protected Object cloneMe() throws CloneNotSupportedException {
        return super.clone(); // throws CloneNotSupportedException
    }
}

公共類 CloneNotSupportedException 擴展異常

拋出表示類 Object 中的 clone 方法已被調用以克隆對象,但該對象的類未實現 Cloneable 接口。 覆蓋克隆方法的應用程序也可以拋出此異常以指示不能或不應克隆對象。

對象不實現任何接口,要使我的 User 類工作,它必須實現Cloneable

對象類 clone() 方法已被 API 級別的受保護訪問修飾符修改。 所以我們不能在沒有繼承的情況下在任何地方訪問它。 因此,在我們調用對象類的 clone() 方法之前,您需要實現 Cloneable 接口。 然后代碼將在運行時正常運行。 否則它將在運行時生成 CloneNotSupportedException。

/*Subclass is my implementing class */

public class SubClass implements Cloneable {

    @Override
    public SubClass clone() throws CloneNotSupportedException {
        return (SubClass) super.clone();
    }
}
import java.util.Scanner;
import java.util.jar.Attributes.Name;
import java.util.Arrays;
public class Main{
    public class man{
        protected void name() {
            System.out.println("hei");
        }
    }
    public class people extends man{
        public int age;

        public int getAge() {
            name();
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "people [age=" + age + "]";
        }
        
        public Object myclone() throws CloneNotSupportedException {
            return this.clone();
        }
    }
    
    public void test() throws CloneNotSupportedException {
        
        people p1 = new people();
        p1.setAge(10);
        System.out.println(p1);
//      NG:
        people p2 = (people)p1.clone();
//      Ok
        people p3 = (people)p1.myclone();
        p1.setAge(10);
        System.out.println(p1);
        System.out.println(p2);
    }
    public static void main(String args[]) throws CloneNotSupportedException{
        new Main().test();
        
    }
}

查看 NG 代碼和 ok 代碼。

//      NG for:The method clone() from the type Object is not visible
        people p2 = (people)p1.clone();
//      Ok
        people p3 = (people)p1.myclone();

為什么? 因為test()不屬於子類。 所以即使通過 peopel 對象p1調用clone() ,它也不是peopel對象的地方。 myclone()正是 people 對象所在的位置。

暫無
暫無

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

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