What are the three ways to obtain a java.lang.Class object in Java, and how do they differ?
answer
- literal = compile-time, no init
- getClass() = runtime type of an instance
- forName = by String, loads + initializes, checked exception
- only forName runs static initializers
- literal works for primitives and arrays
basics
~20 sUse the .class literal (e.g. String.class) when you know the type at compile time, obj.getClass() to get the real runtime type of an existing object, and Class.forName("name") to look up a class by its String name at runtime.
solid answer
~40 sThere are three entry points to a Class object. The class literal Type.class is resolved at compile time, needs no instance, and does not trigger class initialization. obj.getClass() returns the actual runtime type of an existing object, so for a variable typed as the supertype it returns the concrete subclass. Class.forName("fully.qualified.Name") looks the class up by String at runtime; by default it loads AND initializes the class (runs static initializers), uses the caller's class loader, and throws a checked ClassNotFoundException if the name is unknown. A three-argument overload lets you control initialization and the class loader. You pick the literal for known types, getClass() for runtime inspection of an instance, and forName when the type is only known as a string (plugins, JDBC drivers, config).
code
java · 16 lines// 1. class literal — compile-time, no initialization
Class<String> a = String.class;
// 2. getClass() — runtime type of an instance
Object o = "hello";
Class<?> b = o.getClass(); // class java.lang.String
// 3. forName — by name, loads + initializes, checked exception
try {
Class<?> c = Class.forName("java.util.ArrayList");
// load WITHOUT initializing:
Class<?> d = Class.forName("java.util.ArrayList", false,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
// must handle the checked exception
}go deeper
Name the three ways and give one example of each (String.class, obj.getClass(), Class.forName("...")).
Explain the differences: compile-time vs runtime, type safety, and that forName loads and initializes and throws a checked exception.
Discuss initialization semantics precisely, the 3-arg forName overload, class-loader implications, and when each is the right tool (e.g. plugin loading).
Reason about class-loader selection and isolation, lazy vs eager initialization trade-offs, security implications of forName on attacker-controlled names, and how frameworks abstract this.
## What is a Class object? In Java, every loaded type (class, interface, enum, annotation, array, even primitives) is represented at runtime by exactly one immutable instance of `java.lang.Class<T>`. This object is your handle for **reflection**: asking the JVM about a type's name, fields, methods, constructors, modifiers, superclass, and so on. The generic parameter `T` is the type it describes, so `Class<String>` describes `String`. There are three ways to get hold of one. ### 1. The class literal: `Type.class` ```java Class<String> c = String.class; ``` - **Resolved at compile time.** The compiler knows the type, so it is type-safe (`Class<String>`, not raw `Class`). - **Needs no instance.** You write the type's name directly. - **Does NOT initialize the class.** Merely referencing `Foo.class` does not run `Foo`'s static initializers. (Loading may still happen, but the JLS guarantees no *initialization* from a class literal alone.) - Works for primitives too: `int.class`, `void.class`, and array types: `int[].class`, `String[].class`. ### 2. `obj.getClass()` ```java Object o = "hello"; Class<?> c = o.getClass(); // class java.lang.String ``` - A method on `java.lang.Object`, so every object has it. - Returns the **actual runtime type**, not the declared/static type. If a variable is declared `Object` but holds a `String`, you get `String.class`. - Requires a non-null instance — calling it on `null` throws `NullPointerException`. - Its static type is `Class<? extends |the declared type|>` (a wildcard), because the runtime type may be a subtype of what you declared. ### 3. `Class.forName(String)` ```java Class<?> c = Class.forName("java.util.ArrayList"); ``` - Looks the class up by its **fully qualified name as a String** at runtime — the only option when the name is data (plugins, drivers, frameworks, config files). - **Loads and INITIALIZES** the class by default: it runs the static initializers and assigns static fields. This is why the old JDBC idiom `Class.forName("com.mysql.jdbc.Driver")` worked — loading the driver class ran its static block that registered it. - Uses the **caller's class loader**. - Throws the **checked** `ClassNotFoundException` if no such class is found, so you must handle or declare it. - A 3-arg overload, `Class.forName(name, initialize, classLoader)`, lets you suppress initialization (`false`) and choose a specific class loader. ### How to choose | Situation | Use | |---|---| | Type known at compile time | `Type.class` | | You have an instance and want its real type | `obj.getClass()` | | Type known only as a String at runtime | `Class.forName(...)` | ### Key differences summarized - **Initialization:** only `forName` (default) runs static initializers; the literal and `getClass()` do not (the class behind an existing object is, of course, already initialized). - **Compile-time safety:** the literal is fully type-safe; the other two yield wildcard `Class<?>`. - **Exceptions:** only `forName` throws a checked exception. - **Class loader:** `forName` uses the caller's loader (or one you pass); the others use whatever loaded the type already.
- Why did old JDBC code call Class.forName("com.mysql.jdbc.Driver")?Because the 1-arg forName initializes the class, running the driver's static block that registered it with DriverManager. Since JDBC 4.0, ServiceLoader auto-registration makes this call unnecessary.
- How do you load a class by name WITHOUT initializing it?Use the three-argument Class.forName(name, false, classLoader) and pass false for the initialize flag, or use classLoader.loadClass(name), which does not initialize.
saying these in an interview costs you the question
- Saying the .class literal initializes the class (it does not)
- Claiming getClass() returns the declared/static type rather than the runtime type
- Forgetting ClassNotFoundException is checked
- Thinking forName never initializes by default (the 1-arg form does)