Instead of:
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
I'd prefer:
public Person clone() {
try {
return (Person) clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException("This should be impossible ...");
}
}
so callers don't have to handle an exception that can never occur, and don't have to cast.
In the copy-constructor approach, the type switching is better handled polymorphically:
abstract class Person {
...
public abstract Person deepCopy();
}
class Student {
...
public Student deepCopy() {
return new Student(this);
}
}
class Teacher {
...
public Teacher deepCopy() {
return new Teacher(this);
}
}
now the compiler can check that you have provided deep copy for all subtypes, and you don't need any casts.
Finally, note that both the cloning and copy-constructor approach have the same public api (whether the method is called clone()
or deepCopy()
doesn't matter much), so which approach you use is an implementation detail. The copy-constructor approach is more verbose as you provide both a constructor and a method calling that constructor, but it can be more easily generalized to a general type conversion facility, allowing things like:
public Teacher(Person p) {
...
say("Yay, I got a job");
}
Recommendation: Use clone if you only want an identical copy, use copy-constructors if your caller might wish to request an instance of a specific type.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…