1. Overview
In Java, the class java.lang.Class is the entry point of all reflection operations. Once we have an object of java.lang.Class, we can then call the corresponding methods to get the objects of the reflection classes.
In this tutorial, we’ll discuss the differences between two different ways to get an object of java.lang.Class:
- Calling the Object.getClass() method
- Using the .class syntax
2. Short Introduction to the Two Approaches
The Object.getClass() method is an instance method of the Object class. If we have an object, we can call object.getClass() to get the Class object of its type.
Similarly, we can use the ClassName.class syntax to get the Class object of the type. An example can explain it clearly:
@Test
public void givenObjectAndType_whenGettingClassObject_thenTwoMethodsHaveTheSameResult() {
String str = "I am an object of the String class";
Class fromStrObject = str.getClass();
Class clazz = String.class;
assertSame(fromStrObject, clazz);
}
In the test method above, we try to obtain the Class object of the String class using the two ways we’ve mentioned. Finally, the assertion method tells us that the two Class objects are the same instance.
However, there are differences between the two approaches. Let’s take a closer look at them.
3. The Runtime Type vs. the Static Type
Let’s review the previous example quickly. When we call the str.getClass() method, we get the runtime type of the str object. On the other hand, String.class evaluates the String class statically. In this example, the runtime type of str and the String.class are the same.
However, they can be different if class inheritance joins the party. Let’s see two simple classes:
public class Animal {
protected int numberOfEyes;
}
public class Monkey extends Animal {
// monkey stuff
}
Now let’s instantiate an object of the Animal class and do another test:
@Test
public void givenClassInheritance_whenGettingRuntimeTypeAndStaticType_thenGetDifferentResult() {
Animal animal = new Monkey();
Class runtimeType = animal.getClass();
Class staticType = Animal.class;
assertSame(staticType, runtimeType);
}
If we run the test above, we’ll get a test failure:
java.lang.AssertionError: ....
Expected :class com.baeldung.getclassobject.Animal
Actual :class com.baeldung.getclassobject.Monkey
In the test method, even if we instantiated the animal object by Animal animal = new Monkey(); instead of Monkey animal = new Monkey();, the runtime type of the animal object is still Monkey. This is because the animal object is an instance of Monkey at runtime.
However, when we get the static type of the Animal class, the type is always Animal.
4. Handling Primitive Types
When we write Java code, we use primitive types quite often. Let’s try to get a Class object of a primitive type using the object.getClass() approach:
int number = 7;
Class numberClass = number.getClass();
If we try to compile the code above, we’ll get a compilation error:
Error: java: int cannot be dereferenced
The compiler can’t dereference the number variable since it is a primitive variable. Therefore, the object.getClass() method can’t help us to get the Class object of a primitive type.
Let’s see if we can get the primitive type using the .class syntax:
@Test
public void givenPrimitiveType_whenGettingClassObject_thenOnlyStaticTypeWorks() {
Class intType = int.class;
assertNotNull(intType);
assertEquals("int", intType.getName());
assertTrue(intType.isPrimitive());
}
So, we can obtain the Class object of the int primitive type through int.class. In Java version 9 and later, a Class object of primitive type belongs to the java.base module.
As the test shows, the .class syntax is an easy way to get the Class object of a primitive type.
5. Getting the Class Without an Instance
We’ve learned that the object.getClass() method can give us the Class object of its runtime type.
Now, let’s consider the case where we want to obtain a Class object of a type, but we can’t get an instance of the target type because it’s an abstract class, an interface, or some class doesn’t allow instantiation:
public abstract class SomeAbstractClass {
// ...
}
interface SomeInterface {
// some methods ...
}
public class SomeUtils {
private SomeUtils() {
throw new RuntimeException("This Util class is not allowed to be instantiated!");
}
// some public static methods...
}
In these cases, we can’t get the Class objects of those types using the object.getClass() method, but we can still use the .class syntax to obtain the Class objects of them:
@Test
public void givenTypeCannotInstantiate_whenGetTypeStatically_thenGetTypesSuccefully() {
Class interfaceType = SomeInterface.class;
Class abstractClassType = SomeAbstractClass.class;
Class utilClassType = SomeUtils.class;
assertNotNull(interfaceType);
assertTrue(interfaceType.isInterface());
assertEquals("SomeInterface", interfaceType.getSimpleName());
assertNotNull(abstractClassType);
assertEquals("SomeAbstractClass", abstractClassType.getSimpleName());
assertNotNull(utilClassType);
assertEquals("SomeUtils", utilClassType.getSimpleName());
}
As the test above shows, the .class syntax can obtain the Class objects for those types.
Therefore, when we want to have the Class object, but we cannot get an instance of the type, the .class syntax is the way to go.
6. Conclusion
In this article, we learned two different ways to get the Class object of a type: the object.getClass() method and the .class syntax.
Later, we discussed the difference between the two approaches. The following table can give us a clear overview:
object.getClass()
SomeClass.class
Class objects
The runtime type of object
The static Type of SomeClass
Primitive types
—
Works straightforwardly
Interfaces, abstract classes, or classes that can’t be instantiated
—
Works straightforwardly
As always, the full source code of the article is available over on GitHub.