看了网上的一些资料,说一个类如要可以拷贝,需要自己另外重写clone(),但是以下一个程序并没有重写clone()仍然可以拷贝。这是为什么呢?还有为什么一定要声明main()方法可能会抛出一个错误?
public class Student implements Cloneable
{
private int id;
private String name;
public Student()
{
this.id = 744;
this.name = "FL";
}
public Student(int id, String name)
{
this.id = id;
this.name = name;
}
public boolean equals(Object obj)
{
return this.id == ((Student)obj).id;
}
public String toString()
{
return "Student id : " + id + " Name " + name;
}
public static void main(String[] args) 
throws CloneNotSupportedException                 //这里为什么一定得写
{
Student s1 = new Student(101, "WangQiang");
Student s2 = (Student)s1.clone();
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
}
}

解决方案 »

  1.   

    Student s1 = new Student(101, "WangQiang");
    Student s2 = (Student)s1.clone();
    谁说要拷贝?
    Student s2 = s1;直接这样
    Main
    public static void main(String[] args)可以这样写 不一定要抛异常
      

  2.   

    上一楼的是不是说,那是浅拷贝呢?还有一个疑点,clone()是在Object类中实现的,Object类中的clone()又不知道id是什么,怎么能给它赋值?
      

  3.   

    Object 类的 clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。
    Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。 
    你的Student 实现了该接口,不需要在thow exception 了。
    而且 Object的 clone方法是支持大多数复制的。所以你代码没问题。
      

  4.   

    public interface Cloneable此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。 如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常。 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。这里说的公共方法是不是你上面的main方法呢
    所以需要抛出CloneNotSupportedException 异常。
      

  5.   

    上面的说错了,你的Student没有实现 Cloneable 接口,所以你在使用 Object.clone方法需要抛出CloneNotSupportedException 异常。实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)你用公共方法重写clone方法,也就是实现了Cloneable 接口。我觉得应该这样理解
      

  6.   

    楼主,你说的可以拷贝的原因是因为所有的类都继承了Object类,而Object类中写有受保护的 克隆方法,而你又在Student类中去调用colne方法如果你在本类中直接调用colne方法是不需要继承colne方法的, 如果你想在外部内中调用colne方法就必需实现 Cloneable  接口, 我想我这么回答应该能解决楼主的疑问.
      

  7.   

    itliyi  你说的不对,
    Student student1 = new Student(101, "WangQiang");
    Student student2 = student1 ;System.out.println(student2 == student1) ;  
    不就是一个对象吗?
      

  8.   

    没有重写的原因是可以使用超类object默认的clone方法,如果还需加入自己一些个性化处理而不只是单单复杂对象的话就得在你的类中重写clone方法,main方法中加入throws CloneNotSupportedException 是为了让java编译器通过,因为存在你新创建的类未声明可以克隆的情况
      

  9.   

    除了8楼,上面说的都有不正确的地方。首先要明确一点,由于Student类没有实现自己的clone()方法,s1.clone()实际调用的是Object.clone()。1) 无论是否实现了Cloneable接口,只要调用的是Object.clone(),那么就必须throws CloneNotSupportedException,因为Object.clone()有throws这个异常,有抛的就必须有接的。2) Object.clone()按照如下步骤执行:
        (1) 检查执行此方法的当前类有没有应用Clonable接口,如果没有,抛出CloneNotSupportedException异常。
        (2) 如果当前类有应用Clonable接口,则为当前类创建一个新对象(所以s1==s2为false),并将原对象中的所有字段进行一次浅层拷贝(通过赋值进行)。这就是你的程序没有写clone()方法但“看起来”仍然可以克隆的原因。为什么是“看起来”下面会解释。3) 为什么应用了Cloneable接口的类通常还必须重写一个public的clone()方法?这里有两个原因:
        (1) 如果不重写,由于Object.clone()是proteced属性,所以这个clone()方法将无法在外部被调用,更精确地说,无法在当前类之外的任何地方调用。这样就使得克隆失去了用武之地。LZ的例子中刚好是在Student类中调用s1.clone()方法,所以没有问题,但这没有实用价值。
        (2) Object.clone()毕竟只是提供了浅层拷贝,对于基本类型的字段,可以说它成功克隆了。但对于对象型字段,它并没有实现克隆的功能,仅仅做了一个赋值。试运行一下下面的代码就会更清楚了:public class Student implements Cloneable 
    {
    private int id;
    private String name;
    public StringBuffer sb = new StringBuffer(""); public Student() {
    this.id = 744;
    this.name = "FL";
    } public Student(int id, String name) {
    this.id = id;
    this.name = name;
    } public boolean equals(Object obj) {
    return this.id == ((Student) obj).id;
    } public String toString() {
    return "Student id : " + id + " Name " + name;
    } public static void main(String[] args) throws CloneNotSupportedException // 这里为什么一定得写
    {
    Student s1 = new Student(101, "WangQiang");
    Student s2 = (Student) s1.clone();
    System.out.println(s1 == s2);
    System.out.println(s1);
    System.out.println(s2); s1.sb.append("s1's string");
    System.out.println("s2.sb's value = " + s2.sb.toString());
    System.out.println(s1.sb==s2.sb);

    }
    }
    4) 运行时是否抛出CloneNotSupportedException跟你是否重写了clone()方法没有关系,只跟是否应用了Cloneable接口有关系。5) 重写clone()方法不一定需要应用Cloneable接口,因为只有执行Object.clone()方法才会做这个检查。但如果clone()方法中用到了super.clone(),那就必须应用Cloneable接口,原因不难理解。6)应用Cloneable接口的好处在于,它可以允许你安全地调用super.clone(),从而快速地产生一个浅拷贝,之后只需要在重写的公共clone()方法中修改必须修改的字段,如那些不允许共享实例的对象。
      

  10.   

    9楼答得很详细。Object.clone()仅仅是浅拷贝,如果Student类中有非基本类型Field的话,需要重写Object.clone()实现这些非基本类型field拷贝,即深拷贝。