A class loader locates, loads, and defines classes for the JVM. Runtime identity depends on both the class name and the defining loader, so equal names do not guarantee compatible types. section 5.3.3
Same name, different type
A URLClassLoader can load MyClass again from the application’s location. The resulting object prints as MyClass, but instanceof MyClass returns false and casting it throws ClassCastException because the two definitions use different loaders. section 5.3.3
Avoid the loader mismatch by following these rules:
- Treat custom loaders as part of type design, especially in modular or plugin-based applications. section 5.3.3
- Choose the parent loader carefully; parent-first delegation determines which dependencies are loaded by the parent. section 5.3.3
- Prefer compatible shared types or interfaces, and avoid arbitrary casts across loader boundaries. section 5.3.3
import java.net.*;
public class MyClass {
public static void main(String[] args) throws Exception {
URL url = MyClass.class.getResource("."); #1
ClassLoader parent = System.class.getClassLoader(); #2
try (URLClassLoader newLoader =
new URLClassLoader(new URL[]{url}, parent)) {
Class<?> anotherMyClass = newLoader.loadClass("MyClass");
Object o = anotherMyClass.getConstructor().newInstance();
System.out.println("Class: " + o.getClass());
System.out.println("Loader: " + o.getClass().getClassLoader());
System.out.println("Instance of: " + (o instanceof MyClass)); #3
MyClass cls = (MyClass) o; #4
}
}
}
Inspect the minimal URLClassLoader example showing class loading, object creation, instanceof failure, and the cast that triggers ClassCastException. section 5.3.3

