When I run the code below, why does it throw this error?
Exception in thread "main" java.lang.CloneNotSupportedException: Student
at java.lang.Object.clone(Native Method)
at Student.clone(Student.java:44)
at StudentApp.main(StudentApp.java:10)
Here's my main class:
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("湖南省长沙市林科大","1234567",20);
Student stu = new Student("诸葛亮量",20);
stu.setAddress(address);
Student stu2 = (Student)stu.clone();
stu2.setAddress(new Address("湖南省常德市区","484848348",22));
stu2.setName("张飞飞");
stu2.setAge(23);
stu.sayHi();
stu2.sayHi();
}
This is Student class:
public class Student{
private String name;
private int age;
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void sayHi() {
System.out.println("大家好,我是" + this.getName() + "同学,我今年" + this.getAge()开发者_运维技巧
+ "岁了……我的HashCode是:" + this.hashCode()+"。我家庭住址是"+address.getAddress()+",家庭住址的HashCode为:"+address.hashCode());
}
}
This is Address Class:
public class Address {
private String address;
private String tel;
private int roadNum;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public int getRoadNum() {
return roadNum;
}
public void setRoadNum(int roadNum) {
this.roadNum = roadNum;
}
public Address() {
super();
}
public Address(String address, String tel, int roadNum) {
super();
this.address = address;
this.tel = tel;
this.roadNum = roadNum;
}
}
From the javadoc
Invoking Object's clone method on an instance that does not implement the Cloneable interface results in the exception CloneNotSupportedException being thrown.
Have you tried to make your Student
class implement the Cloneable interface?
Instead of attempting to use clone()
, write a copy constructor that takes an instance of a Student and copies it's fields individually. Then you don't need to worry about the semantics of clone
. In your example, this means having a copy constructor on Address as well, since a student has an Address field.
Read Effective Java by Joshua Bloch for reasons why clone should be avoided.
public class Student {
final private String name;
final private int age;
final private Address address;
public Address getAddress() {
return address;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student(Student copyStudent) {
this.name = new String(copyStudent.getName());
this.age = copyStudent.getAge();
this.address = new Address(copyStudent.getAddress());
}
}
From Effective Java
The copy constructor approach and its static factory variant have many advantages over Cloneable/clone: They do not rely on a risk-prone extralinguistic object creation mechanism; they do not demand unenforceable adherence to ill-documented conventions; they do not conflict with the proper use of final fields; they do not require the client to catch an unnecessary checked exception; and they provide a statically typed object to the client. While it is impossible to put a copy constructor or static factory in an interface, Cloneable fails to function as an interface because it lacks a public clone method. Therefore you aren’t giving up interface functionality by using a copy constructor instead of a clone method. Furthermore, a copy constructor (or static factory) can take an argument whose type is an appropriate interface implemented by the class. For example, all general-purpose collection implementations, by convention, provide a copy constructor whose argument is of type Collection or Map. Interface-based copy constructors allow the client to choose the implementation of the copy, rather than forcing the client to accept the implementation of the original. For example, suppose you have a LinkedList l, and you want to copy it as an ArrayList. The clone method does not offer this functionality, but it’s easy with a copy constructor: new ArrayList(l). Given all of the problems associated with Cloneable, it is safe to say that other interfaces should not extend it and that classes designed for inheritance (Item 15) should not implement it. Because of its many shortcomings, some expert programmers simply choose never to override the clone method and never to invoke it except, perhaps, to copy arrays cheaply. Be aware that if you do not at least provide a well-behaved protected clone method on a class designed for inheritance, it will be impossible for subclasses to implement Cloneable.
Student needs to implement Cloneable.
Student and Address both need 'deep' clone, if you don't want to share Address instance both in source and target Student instances:
class Student implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
Student result = (Student)super.clone();
result.setAddress((Address)getAddress().clone());
return result;
}
...
}
class Address implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
...
}
精彩评论