为什么java.lang.Object不能被克隆?

3
当我尝试克隆一个通用的 Object 时,我遇到了编译时错误。为什么?
    Object obj=new Object();
    obj.clone();  // Here compile time error "The method clone() from the type Object is not visible"

每个类都继承Object类,并且clone方法在Object类中是受保护的。 protected方法可以在同一包中访问,以及由子类和所有类作为java.lang.Object的子级。

参见:https://dev59.com/mXM_5IYBdhLWcg3w-4nw - assylias
10个回答

9

由于clone方法在Object类中是受保护的,因此它不是public

唯一可以访问对象的clone()方法的方式是知道它具有公共clone()方法的编译时类型。


1
我知道这个方法是受保护的,但是在同一包中和子类中可以访问受保护的方法,并且所有类都是 java.lang.Object 的子类。 - amicngh
@amicngh - 我不相信仅仅从一个类继承就能使你的对象自动成为同一包中的一部分,是吗? - Steve Townsend
6
我怀疑你不在java.lang包中,并且你没有调用this.clone()而是anObject.clone(),所以你的第二个观点也不适用。 - assylias

4

以下是使克隆工作的最低要求:

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

3

根据Java SE文档

Object类本身不实现Cloneable接口,因此在一个类为Object的对象上调用clone方法将导致运行时抛出异常。


这不是这里所要求的。 - assylias
2
我知道。虽然仍然相关。我为Louis的答案点赞,因为它确定了直接原因。 - Steve Townsend
实际上,这正是此处所要求的。amicngh之所以会出现编译时错误,是因为*.clone()方法实际上并不存在。 - avgvstvs
我仍然认为@Louis的答案是最好的,但需要澄清可见性问题(即编译时与运行时问题)。 - Steve Townsend

1

protected 字段只能从同一包内部访问,因此 Object 类的 clone() 方法只能从位于 java.lang 包中的任何类中访问。


0
我尝试了这段代码:
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
    }
}

public class CloneNotSupportedException extends Exception

抛出此异常表示调用 Object 类中的克隆方法来克隆对象,但该对象的类未实现 Cloneable 接口。重写克隆方法的应用程序也可以抛出此异常,以指示无法或不应克隆对象。

对象没有实现任何接口,为了使我的用户类正常工作,它必须实现 Cloneable 接口。


0
你必须显式地实现Cloneable接口。请参见此线程,其中提供了解释。

0
如果您使用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

[编辑] 最初的问题是关于为什么该方法以这种方式可见。这是因为它只对java.lang包内的方法可访问。它不是为了让程序员能够克隆一个Object。如果您不希望自己的对象被克隆,抛出CloneNotSupportedException正是您想要做的。


0
 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),这两个类位于不同的包中。
受保护的方法可以在相同的包中以及子类(IS A关系)中访问。

0

在API级别中,Object类的clone()方法已被修改为受保护的访问修饰符。因此,我们无法在没有继承的情况下随意访问它。因此,在调用对象类的clone()方法之前,您需要实现Cloneable接口。然后代码将在运行时正确运行。否则,它将在运行时生成CloneNotSupportedException。

/*Subclass is my implementing class */

public class SubClass implements Cloneable {

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

0
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()不属于子类。 所以即使通过人物对象p1调用clone(),它也不是people对象的位置。 myclone()正是人物对象的位置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接