Java Class Class
Last modified: April 13, 2025
The java.lang.Class
class represents classes and interfaces in a
running Java application. It is the entry point for all reflection operations
and provides metadata about classes, including fields, methods, constructors,
and modifiers.
Every object in Java has a Class object that describes its type. The Class class has no public constructor; Class objects are constructed automatically by the JVM when classes are loaded. Understanding Class is essential for advanced Java features like reflection and annotations.
Class Class Methods
The Class class provides numerous methods to examine class metadata at runtime. These include methods to get class name, superclass, interfaces, fields, methods, constructors, and annotations. The class also provides methods to create new instances and check class modifiers.
public final class Class<T> implements ... { public String getName() {...} public Class<? super T> getSuperclass() {...} public Class<?>[] getInterfaces() {...} public Field[] getFields() {...} public Method[] getMethods() {...} public Constructor<?>[] getConstructors() {...} public T newInstance() {...} public boolean isInterface() {...} public boolean isArray() {...} public boolean isPrimitive() {...} // Many more methods... }
The code above shows some key methods of the Class class. These methods allow runtime inspection of class structure and behavior, forming the basis of Java's reflection capabilities.
Getting Class Objects
There are several ways to obtain a Class object in Java. The most common are using the class literal, calling getClass() on an object, and using Class.forName(). Each approach has different use cases and implications.
package com.zetcode; class Sample {} void main() { // 1. Using class literal Class<Sample> cls1 = Sample.class; // 2. Using getClass() on an object Sample obj = new Sample(); Class<? extends Sample> cls2 = obj.getClass(); // 3. Using Class.forName() try { Class<?> cls3 = Class.forName("Sample"); } catch (ClassNotFoundException e) { System.out.println("Class not found: " + e.getMessage()); } System.out.println("Class name via class literal: " + cls1.getName()); System.out.println("Class name via getClass(): " + cls2.getName()); }
This example demonstrates three ways to get Class objects. The class literal is compile-time safe, getClass() works with existing objects, and Class.forName() allows dynamic class loading by name. All three approaches return the same Class object for a given class.
Inspecting Class Metadata
The Class class provides methods to inspect various aspects of a class's structure. This includes getting the class name, package, modifiers, superclass, and implemented interfaces. These methods are fundamental for reflection-based code analysis.
package com.zetcode; interface Greetable { void greet(); } class Person implements Greetable { public void greet() { System.out.println("Hello!"); } } void main() { Class<Person> personClass = Person.class; System.out.println("Class name: " + personClass.getName()); System.out.println("Simple name: " + personClass.getSimpleName()); System.out.println("Package: " + personClass.getPackageName()); System.out.println("Superclass: " + personClass.getSuperclass()); Class<?>[] interfaces = personClass.getInterfaces(); System.out.println("Implemented interfaces:"); for (Class<?> iface : interfaces) { System.out.println(" " + iface.getSimpleName()); } System.out.println("Is interface? " + personClass.isInterface()); System.out.println("Is array? " + personClass.isArray()); }
This example shows how to inspect basic class metadata. We examine the Person class's name, package, superclass, and implemented interfaces. The output demonstrates how reflection can reveal a class's structure at runtime.
Accessing Fields
The Class class provides methods to access a class's fields reflectively. You can get public fields, declared fields (including non-public ones), and inspect field metadata like type and modifiers. Field values can also be get and set reflectively.
package com.zetcode; import java.lang.reflect.Field; class Book { public String title; private String author; protected int pages; } void main() throws Exception { Class<Book> bookClass = Book.class; Book book = new Book(); // Get all public fields (including inherited) Field[] publicFields = bookClass.getFields(); System.out.println("Public fields:"); for (Field field : publicFields) { System.out.println(" " + field.getName()); } // Get all declared fields (regardless of modifier) Field[] allFields = bookClass.getDeclaredFields(); System.out.println("\nAll declared fields:"); for (Field field : allFields) { System.out.println(" " + field.getName() + " (" + field.getType().getSimpleName() + ")"); } // Access private field Field authorField = bookClass.getDeclaredField("author"); authorField.setAccessible(true); // Override access control authorField.set(book, "J.K. Rowling"); System.out.println("\nAuthor set to: " + authorField.get(book)); }
This example demonstrates field access through reflection. We show how to get public fields, all declared fields, and how to access private fields by overriding access control. Note that bypassing access control should be done cautiously as it breaks encapsulation.
Invoking Methods
Reflection allows method invocation at runtime. The Class class provides methods to get method metadata and invoke methods. This is useful for frameworks that need to call methods dynamically, such as dependency injection or testing frameworks.
package com.zetcode; import java.lang.reflect.Method; class Calculator { public int add(int a, int b) { return a + b; } private String repeat(String s, int times) { return s.repeat(times); } } void main() throws Exception { Class<Calculator> calcClass = Calculator.class; Calculator calc = new Calculator(); // Get and invoke public method Method addMethod = calcClass.getMethod("add", int.class, int.class); int result = (int) addMethod.invoke(calc, 5, 3); System.out.println("5 + 3 = " + result); // Get and invoke private method Method repeatMethod = calcClass.getDeclaredMethod("repeat", String.class, int.class); repeatMethod.setAccessible(true); String repeated = (String) repeatMethod.invoke(calc, "Java ", 3); System.out.println("Repeated: " + repeated); // List all public methods (including inherited) System.out.println("\nPublic methods:"); for (Method method : calcClass.getMethods()) { System.out.println(" " + method.getName()); } }
This example shows how to discover and invoke methods reflectively. We demonstrate calling both public and private methods, listing all public methods, and handling method parameters. Method invocation is type-safe at runtime but loses compile-time type checking.
Creating Instances
The Class class can create new instances of classes reflectively. This is useful when the class to instantiate isn't known at compile time. Constructors can also be accessed and invoked reflectively, allowing control over instantiation.
package com.zetcode; import java.lang.reflect.Constructor; class Vehicle { private String type; public Vehicle() { this("Unknown"); } public Vehicle(String type) { this.type = type; } public String getType() { return type; } } void main() throws Exception { // Using newInstance() (deprecated in Java 9+) Class<Vehicle> vehicleClass = Vehicle.class; Vehicle v1 = vehicleClass.getDeclaredConstructor().newInstance(); System.out.println("Default type: " + v1.getType()); // Using specific constructor Constructor<Vehicle> constructor = vehicleClass.getConstructor(String.class); Vehicle v2 = constructor.newInstance("Truck"); System.out.println("Specified type: " + v2.getType()); // Creating instance from class name Class<?> dynamicClass = Class.forName("Vehicle"); Vehicle v3 = (Vehicle) dynamicClass.getConstructor(String.class) .newInstance("Car"); System.out.println("Dynamic type: " + v3.getType()); }
This example demonstrates different ways to create instances reflectively. We show default construction, parameterized construction, and dynamic instantiation from a class name. Note that newInstance() is deprecated in favor of getDeclaredConstructor().newInstance() for better exception handling.
Working with Arrays
The Class class provides special support for array types. You can create arrays reflectively, get component types, and determine array dimensions. Array classes follow special naming conventions in Java reflection.
package com.zetcode; import java.lang.reflect.Array; void main() throws ClassNotFoundException { // Get array class Class<?> stringArrayClass = String[].class; System.out.println("Array class: " + stringArrayClass.getName()); // Create array instance String[] names = (String[]) Array.newInstance(String.class, 3); Array.set(names, 0, "Alice"); Array.set(names, 1, "Bob"); Array.set(names, 2, "Charlie"); System.out.println("\nArray contents:"); for (int i = 0; i < Array.getLength(names); i++) { System.out.println(" " + Array.get(names, i)); } // Multi-dimensional arrays Class<?> int2DArrayClass = Class.forName("[[I"); int[][] matrix = (int[][]) Array.newInstance(int.class, 2, 3); matrix[1][2] = 42; System.out.println("\nMatrix[1][2] = " + matrix[1][2]); // Component type Class<?> componentType = stringArrayClass.getComponentType(); System.out.println("\nComponent type: " + componentType); }
This example shows reflection with arrays. We demonstrate getting array class, creating arrays reflectively, accessing elements, working with multi-dimensional arrays, and examining component types. Array reflection follows Java's internal naming conventions for array types.
Source
Java Class Class Documentation
In this article, we've covered the essential aspects of the Java Class class with practical examples. Understanding Class is crucial for advanced Java features like reflection, annotations, and dynamic class loading.
Author
List all Java tutorials.