Unravel โบ Java concepts โบ JVM and performance
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
A library with several branches.
- 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).
- 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.
- 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
- 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)
- "Jar hell": two versions of the same library on the class path; whichever comes first wins, and the failure appears as an odd NoSuchMethodError
- 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)
- Each Class object records the loader that defined it, and a class's identity is (name, loader)
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(); }}- line 5 uses getClassLoader, the core of Class loading and the class path
- 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.forNamewith 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:
- Types:
ClassLoaderURLClassLoaderNoClassDefFoundErrorClassNotFoundException - Method calls:
getClassLoader()getContextClassLoader()getResourceAsStream()getResource()defineClass()loadClass()getSystemClassLoader()
Part of a learning path
- The JVM and the environment ยท previous: Memory leaks in Java ยท next: Measuring performance and JMH
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.