简体   繁体   中英

Why java.lang.Object can not be cloned?

When i try to clone a generic Object i get compile time error. why?

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

Every class extends Object class and clone method is protected in Object class.

protected methods can be accessed in same package as well as by subclasses and all classes are child of java.lang.Object .

Because clone is protected in the Object class. It's not public .

The only way to get access to an object's clone() method is to know it has a compile-time type that has a public clone() method.

This will be the minimum to get clone working:

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

Per the Java SE docs :

The class Object does not itself implement the interface Cloneable, so calling the clone method on an object whose class is Object will result in throwing an exception at run time.

protected fields can be accessed only from inside the same package, thus clone() method of Object class can be accessed only from any class that is located in java.lang package.

You must explicitely implements Cloneable interface. see this thread which give explanations.

If you use Groovy so that you can bypass the java compilation error, you get this:

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]

If you read the clone API (I will link it) it says that if the Interface isn't implemented, then calling *.clone() will throw a CloneNotSupportedException .

Link to the clone API for java.lang.Object http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#clone%28%29

[EDIT] The Original Question™ asked for why this method is visible in the way it is. This is because it only accessible to methods within the java.lang package. It isn't intended for a programmer to be able to clone an Object . Throwing a CloneNotSupportedException is exactly what you want to do if you don't want your OWN object cloned.

 void method() {

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

}

We can't access the protected method of "Has A" relationship from different package, because your Class package is (com.xxx.yyy) and an Object class package is (java.lang) both the classes are in different package.

protected methods can be accessed in same package as well as by subclasses(IS A relationship)

I tried this code:

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

Thrown to indicate that the clone method in class Object has been called to clone an object, but that the object's class does not implement the Cloneable interface. Applications that override the clone method can also throw this exception to indicate that an object could not or should not be cloned.

Object doesn't implement any interface and to make my User class work it must implement Cloneable

Object class clone() method has modified by protected access modifier in the API level. So we can't access it anywhere without inheritance. So before we invoke object class clone() method you need to implements Cloneable interface. Then Code will run at runtime properly. Otherwise it will generate CloneNotSupportedException at runtime.

/*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();
        
    }
}

see the NG code and ok code.

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

why? cause test() is not belong to the subclass. so even though call clone() by peopel object p1 ,it is not the place of peopel object. The myclone() is the exactly the place of people object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM