How to meaningfully define hashCode and equals for a java.lang.Class<T>?

The implementation of hashCode and equals java.lang.Class inherits from java.lang.Object is meaningful and usually appropriate, as all instances of a class are guaranteed to return the same Class object from getClass(), i.e.

new Integer(2).getClass() == new Integer(3).getClass();

This is somewhat buried in the docs; the javadoc of getClass() writes:

Returns:

The Class object that represents the runtime class of this object.

See Also:

Literals, section 15.8.2 of The Java™ Language Specification.

That section writes:

A class literal evaluates to the Class object for the named type (or for void) as defined by the defining class loader (§12.2) of the class of the current instance.

and section 12.2 writes:

Well-behaved class loaders maintain these properties:

  • Given the same name, a good class loader should always return the same class object.
  • ...

A malicious class loader could violate these properties. However, it could not undermine the security of the type system, because the Java virtual machine guards against this.

And yes, if the same class definition is loaded by different class loaders, the class objects will not be equal. As the runtime treats these as independent classes (who just happen to share the same name, but need not otherwise be similar, let alone binary compatible), this is usually desired.