Instead:
public Object clone() throws CloneNotSupportedException { return super.clone(); }
I would prefer:
public Person clone() { try { return (Person) clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException("This should be impossible ..."); } }
therefore, callers do not need to handle an exception that can never occur, and it does not need to be thrown.
In a copy-constructor approach, type switching is better processed 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 verify that you have provided a deep copy for all subtypes and that you do not need any casts.
Finally, note that the cloning and copy constructor approach has the same open api (regardless of whether the clone() or deepCopy() method is called), so the approach you use is an implementation detail. The copier-constructor approach is more detailed, since you provide both a constructor and a method that calls this constructor, but it is easier to generalize to a general type conversion tool, allowing things like:
public Teacher(Person p) { ... say("Yay, I got a job"); }
Recommendation: use a clone if only an identical copy is required, use copy constructors if your caller can request an instance of a certain type.
meriton
source share