RTTI: Class objects, getClass & class literals
Every loaded type has one Class object. How to obtain it, what it tells you, and the difference between instanceof and isInstance.
Runtime type information
RTTI (Run-Time Type Information) lets a program ask, while it is running, *"what is the exact type of this object?"* The JVM keeps one Class object for every type it loads — String.class, Integer.class, your own Event.class — and that object is the handle through which all RTTI and reflection flow.
There are three ways to get a Class object, and the difference matters on the exam:
// 1. From a live instance — the RUNTIME type, not the declared type:
Object o = "hello";
Class<?> c1 = o.getClass(); // class java.lang.String
// 2. A class literal — known and checked at COMPILE time, no exception:
Class<String> c2 = String.class; // class java.lang.String
// 3. By fully-qualified name as a String — resolved at RUNTIME:
Class<?> c3 = Class.forName("java.lang.String"); // throws ClassNotFoundException
getClass() returns the dynamic (actual) type even when the reference is a supertype. Given Number n = Integer.valueOf(5);, n.getClass() is class java.lang.Integer, not Number. This is the same late-binding idea you saw in polymorphism, exposed as a queryable object.
The Class object is loaded lazily. A class is loaded the first time it is actively used (a static member is accessed, or it is instantiated). Class.forName("X") forces that loading by name — which is exactly why a factory that builds objects from a *string* name (the Greenhouse event factory in the next lesson) is even possible.
Useful Class methods
Class<?> c = "hello".getClass();
c.getName(); // "java.lang.String" — fully qualified
c.getSimpleName(); // "String" — no package
c.getSuperclass(); // class java.lang.Object
c.isInterface(); // false
instanceof vs isInstance
The instanceof operator and Class.isInstance(obj) ask the same question — *is this object that type (or a subtype)?* — but instanceof needs the type spelled out at compile time, while isInstance takes a Class object known only at runtime:
Object o = "hi";
boolean a = o instanceof String; // compile-time type name
Class<?> target = String.class;
boolean b = target.isInstance(o); // dynamic — target could be a variable
Both return true here. Both are also null-safe in the same direction: null instanceof String is false, and target.isInstance(null) is false.