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教程。