the class must document its self-use of overridable methods. (By overridable, we mean nonfinal and either public or protected.)
public boolean remove(Object o)
The
public class Super {
// Broken - constructor invokes an overridable method
public Super() {
overrideMe();
}
public void overrideMe() {
}
}
public final class Sub extends Super {
// Blank final, set by constructor
private final Instant instant;
Sub() {
instant = Instant.now();
}
// Overriding method invoked by superclass constructor
@Override public void overrideMe() {
System.out.println(instant);
}
publicstatic void main(String[] args) {
public boolean remove(Object o)
The
@implSpec
tag was added in Java 8 and used heavily in Java 9. This tag should be enabled by default, but as of Java 9, the Javadoc utility still ignores it unless you pass the command line switch -tag "apiNote:a:API Note:"
.public class Super {
// Broken - constructor invokes an overridable method
public Super() {
overrideMe();
}
public void overrideMe() {
}
}
public final class Sub extends Super {
// Blank final, set by constructor
private final Instant instant;
Sub() {
instant = Instant.now();
}
// Overriding method invoked by superclass constructor
@Override public void overrideMe() {
System.out.println(instant);
}
publicstatic void main(String[] args) {
Sub sub = new Sub();
sub.overrideMe();
}
}
sub.overrideMe();
}
}
If you do decide to implement either
Cloneable
or Serializable
in a class that is designed for inheritance, you should be aware that because the clone
and readObject
methods behave a lot like constructors, a similar restriction applies: neither clone
norreadObject
may invoke an overridable method, directly or indirectly. In the case of readObject
, the overriding method will run before the subclass’s state has been deserialized. In the case of clone
, the overriding method will run before the subclass’s clone
method has a chance to fix the clone’s state. In either case, a program failure is likely to follow. In the case of clone
, the failure can damage the original object as well as the clone. This can happen, for example, if the overriding method assumes it is modifying the clone’s copy of the object’s deep structure, but the copy hasn’t been made yet.
In summary, designing a class for inheritance is hard work. You must document all of its self-use patterns, and once you’ve documented them, you must commit to them for the life of the class. If you fail to do this, subclasses may become dependent on implementation details of the superclass and may break if the implementation of the superclass changes. To allow others to write efficient subclasses, you may also have to export one or more protected methods. Unless you know there is a real need for subclasses, you are probably better off prohibiting inheritance by declaring your class final or ensuring that there are no accessible constructors.
No comments:
Post a Comment