Can Two Classes Have the Same Fully Qualified Name in Java?
What Is a Fully Qualified Name (FQN)?
In Java, a class’s fully qualified name is its package name + class name. For example:
package com.example;
public class MyService {}
FQN = com.example.MyService
But What Really Identifies a Class in the JVM?
Contrary to common belief, in the JVM, a class is not just identified by its name, but by:
(classloader + class name)
This means:
textCopyEditClass A loaded by ClassLoader1 ≠ Class A loaded by ClassLoader2
Even if their bytecode is identical and they come from the same .class
file, the JVM treats them as completely unrelated types if their classloaders differ.
✅ Use Cases Where This Happens Intentionally
1. Servlet Containers (Tomcat, Jetty)
Each deployed WAR file is loaded with its own classloader. So:
com.myapp.Controller
in WAR 1 is not the same as the one in WAR 2- Allows deploying multiple apps with overlapping class names
2. OSGi & Module Systems
Frameworks like OSGi create isolated classloader namespaces for each module (called a “bundle”).
- Each module can define its own version of
com.example.Logger
- Prevents version conflicts
What Happens If You Try to Use Both?
Let’s say you try to pass an object of class com.example.MyService
(loaded by LoaderA
) into a method that expects the same class — but from LoaderB
.
Example:
javaCopyEditClassLoaderA → com.example.MyService
ClassLoaderB → com.example.MyService
MyService obj = new MyService(); // Loaded via A
someComponent.setService(obj); // Expects B's MyService
🔴 Result:
textCopyEditjava.lang.ClassCastException: com.example.MyService (loaded by LoaderA)
cannot be cast to com.example.MyService (loaded by LoaderB)
Even though they look identical in name and structure, the JVM treats them as completely unrelated.