Introduction: Three Names of One Class — How Not to Get Confused?
Every Java developer who has ever looked into the world of reflection has encountered three seemingly identical methods: getName(), getSimpleName() and getCanonicalName(). At first glance, they all return the class name. But as soon as inner classes, arrays, or anonymous classes come into play, confusion begins. This very question has gathered thousands of views on Stack Overflow, and today we will finally figure out the difference.
In this article, we will not just list definitions, but using real code examples show how these methods work. You will learn when to use each one and what pitfalls await you. Let's go!
1. Basic Concepts: What Does Each Method Return?
Before diving into the details, let's define what these terms actually mean in the context of the Java Class API.
- Simple Name (
getSimpleName()): The shortest name. This is just the class name without the package. For inner classes — only the name of the innermost class. - Class Name (
getName()): The full name, but taking into account the internal JVM structure. For regular classes — this is package + class. For inner classes — the separator$is used. For arrays — square brackets are added. - Canonical Name (
getCanonicalName()): The "canonical" name that can be used in source code to declare a variable. It is as close as possible to how you write code: with dots instead of dollar signs.
Sounds abstract? Let's solidify it with code.
2. Example with a Regular Class
Let's start with the simplest — a regular class without nesting.
// File: com/example/MyClass.javapackage com.example;
public class MyClass { public static void main(String[] args) { System.out.println("Simple Name: " + MyClass.class.getSimpleName()); System.out.println("Class Name: " + MyClass.class.getName()); System.out.println("Canonical Name: " + MyClass.class.getCanonicalName()); }}Result:
Simple Name: MyClassClass Name: com.example.MyClassCanonical Name: com.example.MyClassAs you can see, for a regular class, getName() and getCanonicalName() are absolutely identical. getSimpleName() drops the package. No magic.
3. Inner (Nested) Classes: Where the Magic Begins
Now imagine we have an inner class. This is where the key difference becomes apparent.
package com.example;
public class OuterClass { public static class InnerClass { public void printNames() { System.out.println("Simple: " + getClass().getSimpleName()); System.out.println("Class: " + getClass().getName()); System.out.println("Canonical: " + getClass().getCanonicalName()); } }
public static void main(String[] args) { InnerClass inner = new InnerClass(); inner.printNames(); }}Result:
Simple: InnerClassClass: com.example.OuterClass$InnerClassCanonical: com.example.OuterClass.InnerClassThere it is! The difference becomes obvious:
getSimpleName()returned justInnerClass.getName()uses the$symbol to separate the parent and inner class. This is the internal JVM representation.getCanonicalName()uses a dot — the way you would write it in code:OuterClass.InnerClass.
It is because of this $ symbol that many beginners catch bugs when trying to load a class via <