Subtyping
Subtyping (<:)
Subtyping (
subtype <: supertype) is a reflexive and transitive relation on two types, include:- identity
- subclassing
- interface extension
- interface implementation
Subtyping enables upcasting.
To examine subtyping relation of all the above cases
SUPERTYPE.class.isAssignableFrom(SUBTYPE.class)
Identity
Every type is a subtype of itself, by reflexivity of subtyping.
To examine identity relation
A.class == B.classNOTE: Within a given class loader, a class (by name) has exactly one Class object at runtime.
ClassLoader loader1 = ...; ClassLoader loader2 = ...; Class<?> a = loader1.loadClass("mypkg.MyClass"); Class<?> b = loader2.loadClass("mypkg.MyClass"); assertFalse(a == b); // FALSE
Subclassing
class A {}
class B extends A {}
class C extends B {}B is a subtype of A by direct class inheritance.
C is a subtype of A by indirect class inheritance.
Subclassing is about two classes not interfaces.
To examine direct class inheritance
A.class == B.class.getSuperclass()To examine direct and indirect class inheritance
private boolean isSubclass(Class<?> possibleSub, Class<?> possibleSuper) { if (possibleSub == null || possibleSuper == null || possibleSub == possibleSuper) return false; Class<?> clazz = possibleSub; for (; clazz != null && clazz != possibleSuper; clazz = clazz.getSuperclass()) ; if (clazz != null) return true; return false; } isSubclass(C.class, A.class)
NOTE: Object is the root of the class hierarchy. It has no superclass
and is not a subclass of any class. But it is its own subtype, by reflexivity
of subtyping.
Object.class.getSuperclass() == nullInterface extension
interface Intf {}
interface IntfSub extends Intf {}IntfSub is a subtype of Intf by interface extension.
NOTE:
Every interface is a subtype of Object, but not a subclass of Object.
Interfaces have no superclass.
Interface implementation
interface Intf {}
class ClassA implements Intf {}ClassA is a subtype of Intf by implementation.
isAssignableFrom() and isInstance()
if (Super.class.isAssignableFrom(obj.getClass())) {
assert obj instanceof Super; // compile time check: Super is known
}
Class<?> c;
if (c.isAssignableFrom(obj.getClass()) {
assert c.isInstance(obj); // runtime check: type of c is dynamic
}
private void assert_isInstance_isAssignableFrom(Class<?> c, Object o) {
assertTrue(c.isAssignableFrom(o.getClass()));
assertTrue(c.isInstance(o));
}