Java Class 类
最后修改时间:2025 年 4 月 13 日
java.lang.Class 类表示 Java 应用程序中类和接口的运行时表示。 它是反射操作的入口点,允许程序员检索有关类的元数据,例如其字段、方法、构造函数和修饰符。 通过利用 Class 类,开发人员可以动态地分析和操作 Java 类型。
Java 中的每个对象都与一个描述其类型的 Class 对象相关联。 这些对象由 Java 虚拟机 (JVM) 在加载相应的类时自动创建。 由于 Class 类没有公共构造函数,因此无法直接实例化 Class 的实例,而是通过 getClass 和 Class.forName(String className) 等方法获取。
理解 Class 类是高级 Java 功能(如反射、注解和动态类加载)的基础。 反射允许程序在运行时检查和修改类结构,使框架和库能够在没有显式类型定义的情况下执行动态操作。
Class 类方法
Class 类提供了各种方法来检查运行时类元数据。 一些关键方法包括
getName- 返回类的完全限定名称。getSuperclass- 检索当前类的超类。getInterfaces- 返回类实现的接口数组。getDeclaredFields- 提供一个Field对象数组,表示类的字段。getDeclaredMethods- 检索一个Method对象数组,表示类的方法。getDeclaredConstructors- 返回类中可用的Constructor对象数组。getAnnotations- 检索类上声明的注解。newInstance- 使用类的默认构造函数创建一个新的类实例。getModifiers- 返回类的访问修饰符作为整数值。
通过利用这些方法,Java 实现了动态类检查和操作,这在框架、依赖注入、序列化和测试环境中特别有用。
获取 Class 对象
在 Java 中,有几种方法可以获取 Class 对象。 最常见的方法是使用类字面量,在对象上调用 getClass,以及使用 Class.forName。 每种方法都有不同的用例和含义。
class Sample {}
void main() {
Class<Sample> cls1 = Sample.class;
Sample obj = new Sample();
Class<? extends Sample> cls2 = obj.getClass();
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());
}
此示例演示了获取 Class 对象的三种方法。 类字面量是编译时安全的,getClass 适用于现有对象,而 Class.forName 允许按名称动态加载类。 所有这三种方法都为给定的类返回相同的 Class 对象。
检查类元数据
Class 类提供了检查类结构各个方面的方法。 这包括获取类名、包、修饰符、超类和实现的接口。 这些方法是基于反射的代码分析的基础。
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());
}
此示例显示如何检查基本类元数据。 我们检查 Person 类的名称、包、超类和实现的接口。 输出演示了反射如何在运行时揭示类的结构。
访问字段
Class 类提供了以反射方式访问类的字段的方法。 您可以获取公共字段、声明的字段(包括非公共字段),并检查字段元数据,如类型和修饰符。 字段值也可以以反射方式获取和设置。
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));
}
此示例演示了通过反射进行字段访问。 我们展示了如何获取公共字段、所有声明的字段,以及如何通过覆盖访问控制来访问私有字段。 请注意,绕过访问控制应该谨慎进行,因为它会破坏封装。
调用方法
反射允许在运行时调用方法。 Class 类提供了获取方法元数据和调用方法的方法。 这对于需要动态调用方法的框架(如依赖注入或测试框架)非常有用。
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());
}
}
此示例显示了如何以反射方式发现和调用方法。 我们演示了调用公共和私有方法,列出所有公共方法,以及处理方法参数。 方法调用在运行时是类型安全的,但会失去编译时类型检查。
创建实例
Class 类允许通过反射动态实例化对象,即使在编译时不知道对象的类型也可以创建对象。 这在框架、依赖注入和需要灵活对象创建的场景中特别有用。 使用反射,可以动态访问和调用构造函数,从而可以精确控制对象实例化。
static class Vehicle {
private String type;
public Vehicle() {
this("Unknown");
}
public Vehicle(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
public static void main(String[] args) throws Exception {
// Using default constructor reflectively
Class<Vehicle> vehicleClass = Vehicle.class;
Vehicle v1 = vehicleClass.getDeclaredConstructor().newInstance();
System.out.println("Default type: " + v1.getType());
// Using parameterized 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("Main$Vehicle");
Vehicle v3 = (Vehicle) dynamicClass.getConstructor(String.class).newInstance("Car");
System.out.println("Dynamic type: " + v3.getType());
}
此示例演示了以反射方式创建实例的三种方法
- 默认构造函数: 使用
getDeclaredConstructor().newInstance()创建具有默认初始化的实例。 - 参数化构造函数: 检索带有参数的构造函数,并使用特定值实例化对象。
- 动态类加载: 使用
Class.forName()按名称加载类并调用其构造函数。
基于反射的实例化广泛用于 Spring 等框架和依赖注入系统中,从而可以在没有显式类型依赖关系的情况下动态创建对象。 通过利用反射,应用程序可以根据运行时配置实例化类,从而提高模块化和可扩展设计中的灵活性。
使用数组
Class 类为数组类型提供特殊支持。 您可以以反射方式创建数组、获取组件类型并确定数组维度。 数组类在 Java 反射中遵循特殊的命名约定。
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);
}
此示例显示了数组的反射。 我们演示了获取数组类、以反射方式创建数组、访问元素、使用多维数组以及检查组件类型。 数组反射遵循 Java 内部的数组类型命名约定。
来源
在本文中,我们介绍了 Java Class 类的基本方面以及实际示例。 理解 Class 对于高级 Java 功能(如反射、注解和动态类加载)至关重要。
作者
列出所有Java教程。