In Java, what is the difference between these:
Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
If you're unsure about something, try writing a test first.
I did this:
class ClassNameTest {
public static void main(final String... arguments) {
printNamesForClass(
int.class,
"int.class (primitive)");
printNamesForClass(
String.class,
"String.class (ordinary class)");
printNamesForClass(
java.util.HashMap.SimpleEntry.class,
"java.util.HashMap.SimpleEntry.class (nested class)");
printNamesForClass(
new java.io.Serializable(){}.getClass(),
"new java.io.Serializable(){}.getClass() (anonymous inner class)");
}
private static void printNamesForClass(final Class<?> clazz, final String label) {
System.out.println(label + ":");
System.out.println(" getName(): " + clazz.getName());
System.out.println(" getCanonicalName(): " + clazz.getCanonicalName());
System.out.println(" getSimpleName(): " + clazz.getSimpleName());
System.out.println(" getTypeName(): " + clazz.getTypeName()); // added in Java 8
System.out.println();
}
}
Prints:
int.class (primitive): getName(): int getCanonicalName(): int getSimpleName(): int getTypeName(): int String.class (ordinary class): getName(): java.lang.String getCanonicalName(): java.lang.String getSimpleName(): String getTypeName(): java.lang.String java.util.HashMap.SimpleEntry.class (nested class): getName(): java.util.AbstractMap$SimpleEntry getCanonicalName(): java.util.AbstractMap.SimpleEntry getSimpleName(): SimpleEntry getTypeName(): java.util.AbstractMap$SimpleEntry new java.io.Serializable(){}.getClass() (anonymous inner class): getName(): ClassNameTest$1 getCanonicalName(): null getSimpleName(): getTypeName(): ClassNameTest$1
There's an empty entry in the last block where getSimpleName
returns an empty string.
The upshot looking at this is:
Class.forName
with the default ClassLoader
. Within the scope of a certain ClassLoader
, all classes have unique names.toString
or logging operations. When the javac
compiler has complete view of a classpath, it enforces uniqueness of canonical names within it by clashing fully qualified class and package names at compile time. However JVMs must accept such name clashes, and thus canonical names do not uniquely identifies classes within a ClassLoader
. (In hindsight, a better name for this getter would have been getJavaName
; but this method dates from a time when the JVM was used solely to run Java programs.)toString
or logging operations but is not guaranteed to be unique.In addition to Nick Holt's observations, I ran a few cases for Array
data type:
//primitive Array
int demo[] = new int[5];
Class<? extends int[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());
System.out.println();
//Object Array
Integer demo[] = new Integer[5];
Class<? extends Integer[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());
Above code snippet prints:
[I
int[]
int[]
[Ljava.lang.Integer;
java.lang.Integer[]
Integer[]