现在有如下代码
class Address
{
public String detail;
public Address(String detail)
{
this.detail = detail;
}
}class User implements Cloneable
{
int age ;
Address address;
public User(int age)
{
this.age = age;
this.address = new Address("广州天河区");
}
public User clone() throws CloneNotSupportedException
{
return (User)super.clone();
}
}
该User类默认继承Object类,那么在方法clone中的super.clone()应该是调用的Object类中的clone()方法.我的问题是,既然调用的是父类的方法,那么在super.clone()中是如何能够得到子类的Field的信息的,从而用子类的Field信息生成一个Object对象。同时我们都知道如下代码会出错,
class Base
{}
class Sub extends Base
{}public class Test
{
public static void main(String args[])
{
Base base = new Base();
Sub sub = (Sub)base;
}
}
但是为什么我的第一段代码里面 (User)super.clone()却能将Object强制转换为User类,且能够正常使用呢?此外,在重写clone()方法的时候,为什么一定要实现Cloneable接口呢,如果不实现该接口就会有异常产生,为什么?

解决方案 »

  1.   

    我刚看了下。。不对的还请忽略首先父类很容易就能得到子类的所有信息,父类里用this.getClass()就行了。但是父类有必要获得子类的field信息么?我感觉没什么没必要,因为父类不可能知道子类应该如何克隆。API中有这么句话:By convention, the returned object should be obtained by calling super.clone. If a class and all of its superclasses (except Object) obey this convention.我怀疑克隆用了这样一个体系:1、在继承层次中,由Object获得当前实例。传递给下一层。
    2、所有派生类只负责自身层面成员的克隆工作。
    3、传递到最后就完成了所有成员的克隆,也就完成了整个工作。
    “在重写clone()方法的时候,为什么一定要实现Cloneable接口呢”因为Object.clone()有这个要求。
    CloneNotSupportedException异常是由Object.clone()抛出的,要是不调用Object的这个方法,就没必要非得实现Cloneable接口。
      

  2.   

    其实我没闹明白的就是super.clone()这个是父类的clone,它返回类型是Object。既然子类调用的父类clone方法,而且通过父类完成了Field的拷贝,那么父类clone它一定知道子类的各个Field的名字和值。这是怎么做的的啊。而且,调用super.clone()要生成一个子类的对象才能用(User)super.clone()这种方式将super.clone返回的Object类强制转换成子类(User类)。这个我还是无法理解
      

  3.   


    我也同意你的说法。
    但按照你的说法,我的User类只调用了父类的super.clone(),而User类自身并没有做克隆工作。
    但最后我得到的结果却是,子类竟实现了拷贝的。
    例如如下代码:class CsdnTest
    {
    public static void main(String args[]) throws Exception
    {
    User firstUser = new User(25);
    User secondUser = firstUser.clone(); System.out.println(secondUser.age);
    }
    }
    这段代码中,secondUser能够得到firstUser的信息.我的问题就在这里,在子类(User类)中,只是单纯的调用了父类的克隆方法就完成了子类的Field的克隆。就是这点我没闹明白。
      

  4.   

    首先你问super.clone()中是如何能够得到子类的Field的信息的,其实想得到信息也很容易运用反射机制就可以,只要调用在super.clone()方法中调用this.getClass()就ok了(因为clone方法是native属性,具体实现我也不清楚。),还有你问的为什么要实现Cloneable接口,其实这个相当于一个标志,单纯的表示这个类能被克隆(因为这个接口没有任何方法),因为在调用super.clone()时,会先检查这个类是否实现这个接口,否则抛出异常(这些用反射很容易实现,相信你肯定知道)。
      

  5.   


    你说的对哈 Object还是得把所有字段复制一下的。。要不就丢失信息了
      

  6.   


    我还真不知道反射,还没学到那一章。
    你这样说我知道个大概了。意思说,通过反射机制,能够在父类中知道子类的Field信息,甚至生成一个子类对象,对不?
      

  7.   


    对的,如果子类中的Field全是基本类型就很是这样,但是如果某一个属性是一个引用的话就比较麻烦了,就相当于你一楼那个例子User中有一个Address属性,但是Address类却没有实现Cloneable接口,这样会出问题的,你克隆出来的User其实和你原先的User共享了Address信息,你要是修改了原先的Address中的detail,克隆出来的User中也会改变,你可以试试。