Reading Class Names
All the elements that the Reflection API gives access to have names: classes, fields, methods, constructors, or method and constructor parameters. This section covers the retrieving of the names of classes. The Reflection API defines several convention for class names, that are all covered in this section.
Getting the Name of a Class
There are actually several ways to get the name of a class. The two methods you are probably going to use are getCanonicalName()
and getSimpleName()
. The first one gives you the fully qualified name of the class, and the second one gives you just the name, without the package.
On the following example, where the class is explicitly named, what you get is what you expect.
Class<?> arrayList = Class.forName("java.util.ArrayList");
System.out.println("Canonical name: " + arrayList.getCanonicalName());
This prints the following on the console.
Canonical name: java.util.ArrayList
There are cases where the name of the class does not appear explicitly in your code, as you can see it in the following example.
List<String> strings1 = new ArrayList<>();
List<String> strings2 = Arrays.asList("one", "two", "three");
List<String> strings3 = List.of("one", "two", "three");
System.out.println("Canonical name: " + strings1.getClass().getCanonicalName());
System.out.println("Canonical name: " + strings2.getClass().getCanonicalName());
System.out.println("Canonical name: " + strings3.getClass().getCanonicalName());
What you get in this case are the name of the runtime classes:
Canonical name 1: java.util.ArrayList
Canonical name 2: java.util.Arrays.ArrayList
Canonical name 3: java.util.ImmutableCollections.ListN
Simple Name
The simple name of a class is the name as it appears in the source code.
Class<?> c = String.class;
System.out.println("Simple name: " + c.getSimpleName());
Running the previous example gives you the following result.
Simple name: String
Not all classes appear explicitly in the source code. This is the case for anonymous classes and lambda expressions.
Here is the simple name of an anonymous class. Indeed, anonymous classes do not have a simple name.
Object key = new Object() {};
Class<?> c = key.getClass();
System.out.println("Simple name: " + c.getSimpleName());
The result is the following.
Simple name:
You can also print the simple name of a class representing a lambda expression.
Supplier<String> supplier = () -> "Hello";
Class<?> c = supplier.getClass();
System.out.println("Simple name: " + c.getSimpleName());
Running the previous example prints the following. Note that Main
is the simple name of the class in which this lamdba has been declared. So it may vary.
Simple name: Main$$Lambda/0x0000025851003538
Canonical Name
The canonical name of a class is defined in the specification of a language. In a nutshell, it corresponds to its fully qualified name, that is its simple name, prefixed by its package name. Not all classes have canonical names. This is the case for local classes, anonymous classes, and hidden classes that were added in Java SE 15.
When a class does not have a canonical name, then the method getCanonicalName()
returns null.
You can run the previous examples to display the canonical names instead of the simple names, and see the results.
Class<?> c1 = String.class;
System.out.println("Canonical name: " + c1.getCanonicalName());
Object key = new Object() {};
Class<?> c2 = key.getClass();
System.out.println("Canonical name: " + c2.getCanonicalName());
Supplier<String> supplier = () -> "Hello";
Class<?> c3 = supplier.getClass();
System.out.println("Canonical name: " + c3.getCanonicalName());
Running the previous code prints the following. As you can see it, anonymous classes and classes of lambda expressions do not have a canonical name.
Canonical name: java.lang.String
Canonical name: null
Canonical name: null
Type Name
The type name of a class is an informative string for this class. This method is defined in the Type
interface, added in Java SE 8.
Let us examine the difference with the simple name and the canonical name.
Class<?> c1 = String.class;
System.out.println("Type name: " + c1.getTypeName());
Object key = new Object() {};
Class<?> c2 = key.getClass();
System.out.println("Type name: " + c2.getTypeName());
Supplier<String> supplier = () -> "Hello";
Class<?> c3 = supplier.getClass();
System.out.println("Type name: " + c3.getTypeName());
Running the previous code prints the following. Anonymous classes and classes of lambda expressions do have a type name, which is the name of the class created by the compiler for you.
Type name: java.lang.String
Type name: org.devjava.Main$1
Type name: org.devjava.Main$$Lambda/0x00000275a0003748
Getting a Class Name With getName()
The Class.getName()
is yet another way to get the name of a class. It returns the name of the entity (class, interface, array class, primitive type, or void) represented by this Class
object.
For all the classes that are not representing arrays, calling this method is the same as calling Class.getTypeName()
, covered in the previous section of this page. The behavior is different for arrays, as you are going to see it in the next section.
Array Name
Class
objects can also represent arrays, and arrays follow certain naming conventions. The simple name, the type name, and the canonical name are straightforward, as you can see on the following example.
int[] array = {};
Class<?> c = array.getClass();
System.out.println("Simple name: " + c.getSimpleName());
System.out.println("Type name: " + c.getTypeName());
System.out.println("Canonical name: " + c.getCanonicalName());
Running the previous code prints the following.
Simple name: int[]
Type name: int[]
Canonical name: int[]
The name that you get from the Class.getName()
follows a different convention, as you can see it on the following example.
int[] array = {};
Class<?> c = array.getClass();
System.out.println("Name: " + c.getName());
Running the previous code prints the following.
Name: [I
The convention is the following, and is precisely described in the Javadoc of the method Class.getName()
.
The name of an array consists of as many opening square bracket character ([
) as there are nested arrays.
If the type of the array is a primitive type, then the following table is used to encode this primitive type. Note that long
is encoded with a J
, not a L
.
Primitive type | Encoding |
---|---|
boolean | Z |
byte | B |
short | S |
int | I |
long | J |
char | C |
float | F |
double | D |
If the type of the array is a refence type of name N, then the encoding is a L
, followed by the name of this type, followed by the character ;
.
Let us examine the two simple examples.
long[][] bidiLongs = new long[0][];
Class<?> c1 = bidiLongs.getClass();
System.out.println("c1: " + c1.getName());
String[][] bidiString = new String[0][];
Class<?> c2 = bidiString.getClass();
System.out.println("c2: " + c2.getName());
Running the previous code prints the following.
c1: [[J
c2: [[Ljava.lang.String;
Note that in the case of arrays, you can use the string returned by this method to get the class of this array, as you can see it on the following example.
Class<?> c = Class.forName("[[Ljava.lang.String;");
System.out.println("c = " + c);
Running the previous code prints the following.
c = class [[Ljava.lang.String;
Later in the series you will learn how you can use this class to create an array of this type.
Last update: July 19, 2024