> Perhaps more interesting, the three next-most-common superclasses are > "convergent evolution" of an identical class (but with a different name) > > public abstract class ToStringless { > @Override > public final String toString() { > return super.toString(); > } > } > > This class prevents @AutoValue from synthesizing a toString() method, so > Object.toString() gets locked in. Often this is used for a string which may > be "sensitive", but perhaps there are other use cases. Of records with > superclasses, 9% have something like this as their superclass. No state, just > behavior. There's another superclass that also fixes identity-based hashCode > and equals(). If we include this in the count, we get over 10%.
OK, so these fall into the narrow gap between what interfaces can do and what abstract classes can — implement Object methods. That’s interesting, and worth remembering. Of course, it’s also easy to implement toString() in the record (and would be even lower overhead with something like CMB.).