繁体   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