【问题标题】:Why java.lang.Object can not be cloned?为什么 java.lang.Object 不能被克隆?
【发布时间】:2012-07-05 21:15:59
【问题描述】:

当我尝试克隆通用 Object 时,我得到编译时错误。为什么?

    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 的子类。

【问题讨论】:

标签: java clone


【解决方案1】:

因为cloneObject 类中受到保护。不是public

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

【讨论】:

  • 我知道它是受保护的,但受保护的方法可以在同一个包以及子类中访问,并且所有类都是 java.lang.Object 的子类。
  • @amicngh - 我不相信简单地从一个类继承子类会使你的对象自动成为同一个包的一部分,对吗?
  • @amicngh 我怀疑你在java.lang 包中,而且你不是在调用this.clone() 而是anObject.clone(),所以你的第二点也不适用。
【解决方案2】:

根据Java SE docs

Object类本身并没有实现Cloneable接口,所以 在类为 Object 的对象上调用 clone 方法将 导致在运行时抛出异常。

【讨论】:

  • 这不是这里要问的。
  • 我知道。尽管如此,它仍然是相关的。我赞成 Louis 的回答确定了直接原因。
  • 实际上,这正是这里要问的。 amicnh 出现编译时错误的原因是 *.clone() 方法实际上并不存在。
  • 我仍然认为@Louis 的答案是最好的,但可以使用关于可见性的说明(即编译时与运行时问题)
【解决方案3】:

这是让克隆工作的最低要求:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      您必须明确实现 Cloneable 接口。 请参阅this thread,其中给出了解释。

      【讨论】:

        【解决方案6】:

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

        [编辑] The Original Question™ 询问为什么这种方法以它现在的方式可见。这是因为它只能被 java.lang 包中的方法访问。程序员不能克隆Object。如果您不想克隆自己的 OWN 对象,则抛出 CloneNotSupportedException 正是您想要做的。

        【讨论】:

          【解决方案7】:
           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”关系的受保护方法,因为您的Class包是(com.xxx.yyy),而Object类包是(java.lang),这两个类都不同包。

          受保护的方法可以在同一个包中访问,也可以通过子类访问(IS A 关系)

          【讨论】:

            【解决方案8】:

            我试过这段代码:

            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 接口。覆盖的应用程序 clone 方法也可以抛出这个异常来表明一个对象 不能或不应该被克隆。

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

            【讨论】:

              【解决方案9】:

              对象类 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();
                  }
              }
              

              【讨论】:

                【解决方案10】:
                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() 正是人们反对的地方。

                【讨论】:

                  猜你喜欢
                  • 2010-10-22
                  • 2011-10-17
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-11-18
                  • 2022-08-21
                  • 2015-05-29
                  • 1970-01-01
                  相关资源
                  最近更新 更多