What is the difference between canonical name, simple name and class name in Java Class?
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 defaultClassLoader
. Within the scope of a certainClassLoader
, 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 thejavac
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 identify classes within aClassLoader
. (In hindsight, a better name for this getter would have beengetJavaName
; 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)
Also you can commonly reference the Java Language Specification documentation for these types technical Java API details:
- Here's the Java 11 Specification on this subject matter: https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.7
Example 6.7-2.
andExample 6.7-2.
goes overFully Qualified Names
andFully Qualified Names v. Canonical Name
respectively
What's the difference between Name and CanonicalName?
Consider the following program:
package org.test.stackoverflow;
public class CanonicalName {
public static void main(String[] args) {
CanonicalName cn = new CanonicalName();
cn.printClassNames();
}
private Anonymous anony;
private MyAnony myAnony;
public CanonicalName() {
anony = new Anonymous() {
public void printInterface() {
System.out.println("Anony Name: " + getClass().getName());
System.out.println("Anony CanonicalName: " + getClass().getCanonicalName());
}
};
myAnony = new MyAnony();
}
public void printClassNames() {
System.out.println("CanonicalName, Name: " + getClass().getName());
System.out.println("CanonicalName, CanonicalName: " + getClass().getCanonicalName());
anony.printInterface();
myAnony.printInterface();
}
private static interface Anonymous {
public void printInterface();
}
private static class MyAnony implements Anonymous {
public void printInterface() {
System.out.println("MyAnony Name: " + getClass().getName());
System.out.println("MyAnony CanonicalName: " + getClass().getCanonicalName());
}
}
}
Output:
CanonicalName, Name: org.test.stackoverflow.CanonicalName
CanonicalName, CanonicalName: org.test.stackoverflow.CanonicalName
Anony Name: org.test.stackoverflow.CanonicalName$1
Anony CanonicalName: null
MyAnony Name: org.test.stackoverflow.CanonicalName$MyAnony
MyAnony CanonicalName: org.test.stackoverflow.CanonicalName.MyAnony
So it seems that for base classes, they return the same thing. For inner classes, getName()
uses the $
naming convention (i.e. what is used for .class files), and getCanonicalName()
returns what you would use if you were trying to instantiate the class. You couldn't do that with a (little-a) anonymous class, so that's why getCanonicalName()
returns null.
What is the formulation for Java Array class names?
One letter for each primitive, one symbol for arrays, and one letter for reference:
I
= intJ
= longD
= doubleF
= floatZ
= booleanC
= charB
= byteS
= shortLcom/foo/Thing;
= reference 'com.foo.Thing'[
= array of whatever is next (so,[[I
is anint[][]
).
This is VM-speak for type signatures. For example, the signature of:
public boolean[] foo(String[] args, int count) { ... }
is: ([Ljava/lang/String;I)[Z
.
It is for machines and not humans; it is easy to parse (you just move forward, no need to look-ahead).
This is not the 'class name' of a thing; the usual name for this construct is 'vm name'. Note that generics just disappear from these; the VM name of List<String>
is Ljava/util/List;
. It's why you can't override methods if the two methods end up with the same name, param types, and return type if you remove all generics.
Should I use a class name when referencing a static field in that class?
I agree with whatever being mentioned in the comments. Apart from this, I keep readability of the code in mind and then decide. Following code fragment gives an idea on the same:
public class Engine {
private static boolean isOn = false;
public static void doWork1() {
if (isOn) { // check if engine is on
// do some work
}
}
public static void doWork2() {
if (Engine.isOn) {
// do some work
}
}
...
}
You can see that doWork2()
method by using the class name increased the code readability even without adding any comment to the code.
Java code snippet to shorten package name from fully qualified class name
You can use NameAbbreviator from log4j-core.
NameAbbreviator n = NameAbbreviator.getAbbreviator("1.");
StringBuilder sb = new StringBuilder();
n.abbreviate("com.test.Student", sb);
System.out.println(sb); /* Result: c.t.Student */
Related Topics
Is There Any Good and Free Date and Time Picker Available for Java Swing
Java Sorting Based on Enum Constants
How to Set a Long Java Classpath in Windows
Java's Virtual MAChine's Endianness
How to Read Text from Hidden Element with Selenium Webdriver
When and How Are Classes Garbage Collected in Java
Why Are Interface Method Invocations Slower Than Concrete Invocations
How to Increase the Java Heap Size in Netbeans
Javafx and Maven: Nullpointerexception: Location Is Required
JSONobject - How to Get a Value
How to Pass Console Arguments to Application in Eclipse
Lists with Wildcards Cause Generic Voodoo Error
Convert .Jar to an Osx Executable
How to Make a Countdown Timer in Java
A Simple Http Server with Java/Socket
Capture Generated Dynamic Content at Server Side
Does Java Have Any Mechanism for a Vm to Trace Method Calls on Itself, Without Using Javaagent, etc