ZetCode

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.

Main.java
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.

Main.java
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.

Main.java
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.

Main.java
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.

Main.java
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.

Main.java
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

My name is Jan Bodnar, and I am a dedicated programmer with many years of experience in the field. I began writing programming articles in 2007 and have since authored over 1,400 articles and eight e-books. With more than eight years of teaching experience, I am committed to sharing my knowledge and helping others master programming concepts.

List all Java tutorials.