Saturday, October 26, 2019

What is the difference between canonical name, simple name and class name in Java Class?



In Java, what is the difference between these:



Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();



I have checked the Javadoc multiple times and yet this never explains it well.
I also ran a test and that didn't reflect any real meaning behind the way these methods are called.


Answer



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:




  • the name is the name that you'd use to dynamically load the class with, for example, a call to Class.forName with the default ClassLoader. Within the scope of a certain ClassLoader, all classes have unique names.

  • the canonical name is the name that would be used in an import statement. It might be useful during 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.)


  • the simple name loosely identifies the class, again might be useful during toString or logging operations but is not guaranteed to be unique.

  • the type name returns "an informative string for the name of this type", "It's like toString(): it's purely informative and has no contract value" (as written by sir4ur0n)


No comments:

Post a Comment

hard drive - Leaving bad sectors in unformatted partition?

Laptop was acting really weird, and copy and seek times were really slow, so I decided to scan the hard drive surface. I have a couple hundr...