Introduction
This article is a continuation of a series of articles describing the often forgotten about methods of the Java language's base Object class. Below are the methods of the base Java Object present in all Java objects due to the implicit inheritance of Object along with links to each article of this series.
The focus of this article is the getClass()
method, which is used to access metadata about the class of the object you are working with.
The getClass() Method
The somewhat confusing or misunderstood Object method getClass()
returns an instance of the Class class, which contains information about the class that getClass()
was called from. Whew, if you're not confused already by that last statement, good for you, because I am and I wrote it!
Let me try to unpack that sentence with a demonstration of how this might be used. Below you will find the Person
class I used in the initial article on the Object class's toString()
method.
package com.adammcquistan.object;
import java.time.LocalDate;
public class Person {
private String firstName;
private String lastName;
private LocalDate dob;
public Person(String firstName, String lastName, LocalDate dob) {
this.firstName = firstName;
this.lastName = lastName;
this.dob = dob;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public LocalDate getDob() {
return dob;
}
public void setDob(LocalDate dob) {
this.dob = dob;
}
@Override
public String toString() {
return "<Person: firstName=" + firstName + ", lastName=" + lastName + ", dob=" + dob + ">";
}
}
Let's focus on the overridden toString()
method, which lists the name of the class, Person, along with the values of the instance's fields. Instead of "hard-coding" the name of the class, Person, in the string itself I could have actually used the getClass()
method to return an instance of the Class class, which will contain that info and allow me to use it like so:
public class Person {
// omitting everything else remaining the same
@Override
public String toString() {
Class c = getClass();
return "<" + c.getName() + ": firstName=" + firstName + ", lastName=" + lastName + ", dob=" + dob + ">";
}
}
This would lead to replacing the original hard-coded "Person" text with the fully qualified class name of "com.adammcquistan.object.Person". The Class class is packed full of different methods that allow you to identify all kinds of things about the class object that getClass()
was called on.
For example, if I wanted to get a more simplified toString()
representation of my Person
class I could simply swap out the c.getName()
call with c.getSimpleName()
like shown below. This in turn would return "Person" instead of the fully qualified class name "com.adammcquistan.object.Person".
public class Person {
// omitting everything else remaining the same
@Override
public String toString() {
Class c = getClass();
return "<" + c.getSimpleName() + ": firstName=" + firstName + ", lastName=" + lastName + ", dob=" + dob + ">";
}
}
A major difference in the semantics of how getClass()
is used in comparison to the other Object
methods is that getClass()
cannot be overridden because it is declared as a final
method.
What is the Class object Good For?
At this point you may be asking yourself, "Ok I guess it is pretty cool that I can get information about a class by calling getClass() and retrieving its Class object representation, but how is this useful to me as a programmer?". Believe me, I've asked myself this question as well and my general conclusion has been... it's not. At least it is not really from an everyday programmer's perspective. However, if you happen to be a library or framework developer then you are likely to get very familiar with the information and behavior of Class
objects because it is essential for the concept known as reflection.
Reflection allows for two primary things: (i) runtime investigation of objects and their contents and, (ii) dynamic access to fields and execution of methods during runtime.
Item number one was already demonstrated above by using getClass()
to get a runtime representation of the Person
class to access either the fully qualified or simple class name in a modified version of the toString()
method.
The second item is a bit more involved to whip up an example for, but it is something that is quite helpful to be able to access metadata on a class. Some of the information that you can interrogate an instance of Class
for are things like constructors, fields, and methods plus other things like inheritance hierarchies of a class, like its super classes and interfaces.
An example of this is the ability to use debuggers in an IDE like Eclipse and Netbeans to see the member's and their values in a class while the program is in execution.
Take for example the following:
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
public class Main {
public static void main(String[] args) {
Person me = new Person("Adam", "McQuistan", LocalDate.parse("1987-09-23"));
Class c = me.getClass();
for (Field f : c.getDeclaredFields()) {
f.setAccessible(true);
try {
System.out.println(f.getName() + " = " + f.get(me));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Would output the following:
firstName = Adam
lastName = McQuistan
dob = 1987-09-23
Again, no non-masochist would probably ever do this in regular everyday programming, but you will see this type of thing done often in frameworks.
Conclusion
In this article I described the meaning and use of the mysterious getClass()
method of the Java Object class. I have shown how it can be used to get metadata on a class instance such as the name of the class of an object at runtime as well as provided an explanation of why accessing a Class instance may be useful.
As always, thanks for reading and don't be shy about commenting or critiquing below.