Previous in the Series
Current Tutorial
Retrieving Classes
Next in the Series

Previous in the Series: Introducing the Reflection API

Next in the Series: Reading Class Names

Retrieving Classes

The entry point for all reflection operations is java.lang.Class. Aside from java.lang.reflect.ReflectPermission, none of the classes in java.lang.reflect have public constructors. To get to these classes, it is necessary to invoke appropriate methods on Class. There are several ways to get a Class depending on whether the code has access to an object, the name of class, a type, or an existing Class.

Every type is either a reference or a primitive. Classes, enums, records, lambdas, and arrays (which all inherit from java.lang.Object) as well as interfaces are all reference types. Examples of reference types include java.lang.String, all the wrapper classes for primitive types such as java.lang.Double, the interface java.io.Serializable, and the enum java.nio.file.StandardOpenOption. There is a fixed set of primitive types: boolean, byte, short, int, long, char, float, and double.

For every type of object, the Java virtual machine instantiates an immutable instance of java.lang.Class which provides methods to examine the runtime properties of the object including its members and type information. The class java.lang.Class also provides the ability to create new classes and objects. Most importantly, it is the entry point for all the Reflection APIs. This section explains how you can retrieve the instance of java.lang.Class that you need.

 

Getting the Class of an Object

If an instance of an object is available, then the simplest way to get its Class is to invoke Object.getClass(). Of course, this only works for reference types which all inherit from Object. Some examples follow.

Getting a Simple Class

The following invokes the getClass() method on an instance of the String class. It returns the Class object for the String class.

Class<?> c = "foo".getClass();
System.out.println("class: " + c);

Running the previous code displays the following:

class: class java.lang.String

Note that the toString() method of the class Class adds class in front of the name of the class.

There is a unique console associated with the virtual machine which is returned by the static method System.console(). The value returned by getClass() is the Class corresponding to java.io.Console.

Class<?> c = System.console().getClass();
System.out.println("class: " + c);

Running the previous code displays the following. Note that java.io.Console is a sealed class, with only one permitted extension: ProxyingConsole. This class is not public (you can find it with your IDE for instance), so you cannot use it in your code. It is provided to you at runtime by the JDK.

class: c: class java.io.ProxyingConsole

Getting an Enum Class

SATURDAY is an instance of the enum Days; thus, in the following example getClass() returns the Class corresponding to the enumeration type Days.

enum Days {SATURDAY, SUNDAY}

Class<?> c = Days.SATURDAY.getClass();
System.out.println("class: " + c);

Note that what the previous code displays depends on how you declare your enumeration: the package you put it in, and if you declare this enumeration in its own class, or as a local or inner class.

class: class org.devjava.Days

Getting an Array Class

Since arrays are Objects, it is also possible to invoke getClass() on an instance of an array. The returned Class corresponds to an array with component type byte.

byte[] bytes = new byte[1024];
Class<?> c = bytes.getClass();
System.out.println("class: " + c);

Running the previous example displays the following.

class: class [B

The string [B corresponds to an array of bytes. It uses a special syntax that we will cover later in this section.

Getting a Runtime Class

In the following case, java.util.Set is an interface to an object of type java.util.HashSet. The value returned by getClass() is the class corresponding to java.util.HashSet.

import java.util.HashSet;
import java.util.Set;

Set<String> s = new HashSet<String>();
Class<?> c = s.getClass();
System.out.println("class: "+c);

Running the previous example displays the following.

class: class java.util.HashSet

Note that the generic type of this set is not there, due to type erasure. You will a way to get the generic type of elements see later in this chapter.

Getting a Lambda Class

Lambda expressions also have classes that you can get, even if it is probably not advisable to do so.

Supplier<String> supplier = () -> "Hello";
Class<?> c = supplier.getClass();
System.out.println("class: " + c);

Running the previous example displays the following. Running it on your machine may produce a different result.

class: class org.devjava.Main$$Lambda/0x00000290d4003538

Getting an Anonymous Class

Anonymous classes are classes created for you by the compiler.

Object key = new Object() {};
Class<?> c = key.getClass();
System.out.println("class: " + c);

Running the previous example displays the following. Running it on your machine may produce a different result.

class: class org.devjava.Main$1

 

The .class Syntax

If the type is available but there is no instance then it is possible to obtain a Class by appending .class to the name of the type. This is also the easiest way to obtain the Class for a primitive type.

Calling getClass() on a primitive type gives you a compile time error, as you can see on the following example.

boolean b = true;
Class<?> c = b.getClass();   // compile-time error

Note that the statement boolean.getClass() would produce a compile-time error because a boolean is a primitive type and cannot be dereferenced. The .class syntax returns the Class corresponding to the type boolean.

boolean b = true;
Class<?> c = boolean.class;  // correct
System.out.println("class: " + c);

Running the previous example displays the following.

class: boolean

You can also use this syntax on reference types. In the following example, the variable c is the Class corresponding to the type java.io.PrintStream.

Class<?> c = java.io.PrintStream.class;
System.out.println("class: " + c);

Running the previous example displays the following.

class: class java.io.PrintStream

The .class syntax may be used to retrieve a Class corresponding to a multidimensional array of a given type.

Class<?> c = int[][][].class;
System.out.println("class: " + c);

Running the previous example displays the following.

class: class: class [[[I

This special syntax is explained later in this section.

 

The Method Class.forName()

If the fully-qualified name of a class is available, it is possible to get the corresponding Class using the static method Class.forName(). This cannot be used for primitive types, but can be used for any array, including arrays of primitive types. The syntax for names of array classes is described by Class.getName(). This syntax is applicable to references and primitive types.

Class<?> c = Class.forName("java.lang.String");

This statement returns the class object from the given fully-qualified name. If this class does not exist, this method throws a ClassNotFoundException.

Here are two examples for a simple array and a bidimensional array.

Class<?> simpleDoubleArray = Class.forName("[D");

Class<?> bidiStringArray = Class.forName("[[Ljava.lang.String;");

The variable simpleDoubleArray will contain the Class corresponding to an array of primitive type double (that is, the same as double[].class). The bidiStringArray variable will contain the Class corresponding to a two-dimensional array of String (that is, identical to String[][].class).

 

The Method Class.forPrimitiveName()

A method Class.forPrimitiveName() was added to the class Class in Java SE 22. This method returns the corresponding class for any primitive type, including void.

Here is an example of this method in action.

Class<?> c = Class.forPrimitiveName("int");
System.out.println("class: " + c);

Running the previous example displays the following.

class: int

This method returns null if you pass a string that is not a primitive type, and throws a NullPointerException is you pass null.

 

Retrieving a Primitive Type From a Wrapper Type

Each of the primitive types and void has a wrapper class in java.lang that is used for the boxing of primitive types to reference types.

For instance, the class java.lang.Double wraps the primitive type double whenever an Object is required.

Each wrapper class contains a static field named TYPE which is equal to the Class for the primitive type being wrapped. This field is public and static, so you can use it wherever you need it.

Here is an example on how you can use this TYPE field.

Class<?> c = Double.TYPE;
System.out.println("class: " + c);

Running the previous code displays the following.

class: double

You can also use it with the Void type.

Class c = Void.TYPE;

Void.TYPE is identical to void.class.

 

Getting a Class From Another Class

There are several Reflection APIs which return classes but these may only be accessed if a Class has already been obtained either directly or indirectly.

Getting the Super Class of a Class

The Class.getSuperclass() method returns the only super class of a given class. It returns null for the Object class.

The following code prints the super classes of the NullPointerException class.

Class<?> c = NullPointerException.class;
while (c != null) {
    System.out.println("class: " + c);
    c = c.getSuperclass();
}

Running the previous example prints the following.

class: class java.lang.NullPointerException
class: class java.lang.RuntimeException
class: class java.lang.Exception
class: class java.lang.Throwable
class: class java.lang.Object

Getting the Implemented Interfaces of a Class

The Class.getInterfaces() method returns an array of the interfaces directly implemented by a given class. It does not return any interface implemented by the super types of the given class. If the given class is actually an interface, then it returns the interfaces directly extended by the given interface.

You can test this method with the following code.

Class<?> c = String.class;
Class<?>[] implementedInterfaces = c.getInterfaces();
for (Class<?> implementedInterface : implementedInterfaces) {
    System.out.println("i: " + implementedInterface);
}

Running the previous example gives you the following result.

i: interface java.io.Serializable
i: interface java.lang.Comparable
i: interface java.lang.CharSequence
i: interface java.lang.constant.Constable
i: interface java.lang.constant.ConstantDesc

You can also call this method on an array type, as in the following example.

int[] ints = {0, 1, 2};
Class<?> superClass = ints.getClass().getSuperclass();
System.out.println("Super class: " + superClass);
Class<?>[] interfaces = ints.getClass().getInterfaces();
System.out.println("Implemented interfaces");
Arrays.stream(interfaces).forEach(System.out::println);

The result is the following.

Super class = class java.lang.Object
Implemented interfaces
interface java.lang.Cloneable
interface java.io.Serializable

It shows two things.

  1. At runtime, arrays are object, and as such, their type extends Object.
  2. this type also implements Cloneable and Serializable.

Getting the Public Member Classes of a Class

The Class.getClasses() method returns all the public classes, interfaces, records, and enums that are members of the class, and of all its super classes.

The following example shows this method in action on the Character class.

Class<?> c = Character.class;
for (var memberClass: c.getClasses()) {
    System.out.println("class: " + memberClass);
}

Running the previous example prints the following.

class: class java.lang.Character$UnicodeBlock
class: class java.lang.Character$UnicodeScript
class: class java.lang.Character$Subset

Getting all the Member Classes of a Class

The Class.getDeclaredClasses() method returns an array all the member classes of this class, whether they are public, protected, package protected, or private. Inherited member classes are not returned.

You can try this method on the same Character class as previously, with the following code.

Class<?> c = Character.class;
for (var memberClass: c.getDeclaredClasses()) {
    System.out.println("class: " + memberClass);
}

And you can see that the result is not the same. The class java.lang.Character$CharacterCache is in the array. It is a private member class of the Character class. It was not returned previously, because the Class.getDeclaredClasses() method only returns public members.

class: class java.lang.Character$CharacterCache
class: class java.lang.Character$UnicodeBlock
class: class java.lang.Character$UnicodeScript
class: class java.lang.Character$Subset

Getting the Declaring Class of a Class

The Class.getDeclaringClass() returns the class in which this class is declared. If this class is not a member class of any class, then this method returns null.

The following example shows this method in action on the Character.UnicodeBlock class.

Class<?> c = Character.UnicodeBlock.class;
Class<?> declaringClass = c.getDeclaringClass();
System.out.println("class: " + declaringClass);

Running the previous example prints the following. Indeed, the Character.UnicodeBlock class is a member of the class Character.

class: class java.lang.Character

Note that the declaring class of an anonymous class is null, as you can see it on the following example.

var key = new Object() {};
Class<?> anonymousClass = key.getClass();
Class<?> declaringClass = anonymousClass.getDeclaringClass();
System.out.println("class: " + declaringClass);

Running this code gives you the following result.

class: null

Getting the Enclosing Class of a Class

The Class.getEnclosingClass() method returns the immediately enclosing class of a given class. It returns null for a class that is not a member of any class.

There are cases where the enclosing class and the declaring class are the same, as it is the case on the following example.

Class<?> c = Character.UnicodeBlock.class;
Class<?> enclosingClass = c.getEnclosingClass();
System.out.println("class: " + enclosingClass);

Running the previous example prints the following. For this class, calling Class.getDeclaringClass() and Class.getEnclosingClass() returns the same class.

class: class java.lang.Character

But in the case of an anonymous class, the result is not the same. The enclosing class is the class in which the anonymous class is declared. You can see it on the following example.

var key = new Object() {};
Class<?> anonymousClass = key.getClass();
Class<?> declaringClass = anonymousClass.getDeclaringClass();
System.out.println("class: " + declaringClass);

The previous code returns the following. Note that you may have a different result.

class: class Main

 

Getting the Declaring Class of a Class Member

Fields, methods, and constructors are modeled by their own class in the Reflection API: Field, Method, and Constructor. They all implement a common interface: Member. This interface has several methods, among them is the Member.getDeclaringClass() method, that returns the class in which the corresponding member is declared.

Fields, methods, and constructors are covered in detail later in this chapter, as well as the other methods of the Member interface.


Last update: July 19, 2024


Previous in the Series
Current Tutorial
Retrieving Classes
Next in the Series

Previous in the Series: Introducing the Reflection API

Next in the Series: Reading Class Names