BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ JVM and performance

Java language

Class loading and the class path

A class loader finds the bytes of a class (from a jar or folder) and turns them into a Class object the first time the class is needed.

Learn these first

At a glance

Mental model

A library with several branches.

What happens, in order
  1. 1Loading is lazy: the JVM loads a class when it first runs new, a static call or a field access, not at startupThen it links (verifies) and initialises (runs static blocks).
  2. 2Parent delegation: a loader asks its parent firstThe chain is bootstrap (JDK core) then platform then application (class path) loader; servers add loaders per web application.
  3. 3getClass().getResourceAsStream("/config.yml") loads a file from the class path using the same loader; Thread.currentThread().getContextClassLoader() is what frameworks use to find user classes
  4. 4Errors: ClassNotFoundException (a name looked up at run time does not exist), NoClassDefFoundError (it existed when compiled but is missing or failed to initialise now), NoSuchMethodError (a different version of a jar is on the class path), ClassCastException with identical names (two loaders)
Remember
Watch out
Using Class.forName with the wrong class loaderTwo copies of one library on the class pathStatic state assumed to be global in a server with several loadersRelative file paths instead of class-path resources
Example (highlighted lines explain it)
import java.io.*;import java.util.Properties;public class Resources {  static Properties load(String name) throws IOException {    try (InputStream in = Resources.class.getClassLoader().getResourceAsStream(name)) {      if (in == null) throw new FileNotFoundException(name + " is not on the class path");      Properties p = new Properties();      p.load(in);      return p;    }  }  static ClassLoader loader() { return Thread.currentThread().getContextClassLoader(); }}
  1. line 5 uses getClassLoader, the core of Class loading and the class path
  2. line 12 uses ClassLoader, the core of Class loading and the class path
Read the full explanation (about 2 min)

A class loader finds the bytes of a class (from a jar or folder) and turns them into a Class object the first time the class is needed. The same class name loaded by two loaders gives two different classes.

A mental model

A library with several branches. A request goes to the main branch first; only if they do not have the book does the local branch try. Two branches holding their own copy of the same title give you two different books that cannot be swapped.

How it works

Loading is lazy: the JVM loads a class when it first runs new, a static call or a field access, not at startup. Then it links (verifies) and initialises (runs static blocks).

Parent delegation: a loader asks its parent first. The chain is bootstrap (JDK core) then platform then application (class path) loader; servers add loaders per web application.

getClass().getResourceAsStream("/config.yml") loads a file from the class path using the same loader; Thread.currentThread().getContextClassLoader() is what frameworks use to find user classes.

Errors: ClassNotFoundException (a name looked up at run time does not exist), NoClassDefFoundError (it existed when compiled but is missing or failed to initialise now), NoSuchMethodError (a different version of a jar is on the class path), ClassCastException with identical names (two loaders).

Going deeper

"Jar hell": two versions of the same library on the class path; whichever comes first wins, and the failure appears as an odd NoSuchMethodError. Use mvn dependency:tree or gradle dependencies to find duplicates.

Hot redeploys in application servers can leak class loaders when a thread, driver or ThreadLocal keeps a reference to a class of the old loader (the Metaspace OutOfMemoryError).

Custom class loaders power plug-ins, hot reload and isolation; the module system (module-info.java) adds stricter encapsulation on top.

Under the hood

Each Class object records the loader that defined it, and a class's identity is (name, loader). The JVM verifies bytecode before running it, and parent delegation keeps core classes like java.lang.String from being replaced by user code.

Common mistakes

  • Using Class.forName with the wrong class loader.
  • Two copies of one library on the class path.
  • Static state assumed to be global in a server with several loaders.
  • Relative file paths instead of class-path resources.

How Unravel recognises it

When you paste code, Unravel looks for these signs of class loading and the class path. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Class loading and the class path?

A class loader finds the bytes of a class (from a jar or folder) and turns them into a Class object the first time the class is needed. The same class name loaded by two loaders gives two different classes.

What are the most common mistakes with Class loading and the class path?

Using Class.forName with the wrong class loader. Two copies of one library on the class path. Static state assumed to be global in a server with several loaders. Relative file paths instead of class-path resources.

How can I see Class loading and the class path in real code?

Paste your own Java into Unravel and it will point out where class loading and the class path appears, explain how it works at the detail level you choose, and draw the flow of the code around it.