在 Java 中一切皆是类(Class)。我们习惯说 Java 的体系是面向对象编程。其实,Java 是面向类编程!所以再怎么了解 Class 本身也不会过。
关键字:Class, Java, Java Class, Java 源码
静态方法
-
Class.forName(String className)- 根据类的全限定名加载并初始化类。常用于动态加载类。频繁调用此方法可能影响性能,应考虑缓存 Class 对象。
// 或 ClassLoader loader = Thread.currentThread().getContextClassLoader(); ClassLoader loader = this.getClass().getClassLoader() // 不初始化类,而是缓存 Class 对象 Class<?> clazz = Class.forName("com.example.MyClassName", false, loader); -
Class.forName(String name, ClassLoader loader)- 根据类的全限定名,使用特定的类加载器加载并初始化类。 -
Class.forName(String name, boolean initialize, ClassLoader loader)- 根据类的全限定名,使用特定的类加载器加载,并依据 initialize 是否初始化类。
实例方法
-
Class.instance.toString()- 将 class 对象转换为字符串。// 也可以使用以下方式调用。后面的所有实例方法皆是。 object.getClass().toString() -
Class.instance.toGenericString()- 返回一个描述该类型(类、接口、修饰符、枚举)的字符串信息,包括:类型修饰器、类型名称、全名。 -
Class.instance.newInstance()- 返回 class 对象所表示的类的实例。此类本身不能是Class、接口 等无法实例化的类。 -
Class.instance.isInstance(Object obj)- 判断对象是否为 class 对象所表示的类(或 子孙类)的实例。 -
Class.instance.isAssignableFrom(Class<?> cls)- 判断 class 对象所表示的类/接口是否与给定的 class 对象所表示的类/接口相同,或是其超类/超接口。常用于检查类的类型兼容性。 -
Class.instance.isInterface()- 判断 class 对象所表示的类型是否为一个接口。 -
Class.instance.isArray()- 判断 class 对象所表示的类型是否为一个数组。 -
Class.instance.isPrimitive()- 判断 class 对象所表示的类型是否为一个原始类(如 Boolean、Integer、Void 等)。 -
Class.instance.isAnnotation()- 判断 class 对象所表示的类型是否为一个注解。 -
Class.instance.isSynthetic()- 判断 class 对象所表示的类型是否为一个合成类。合成类是合成成员的一种,包括了合成类、合成方法、合成字段,用于支持 Java 的内部机制。
合成成员:由 Java 编译器自动生成的(而非开发者显式编写的)类、方法、字段。如:
- 嵌套类访问外部类私有成员 时生成的访问器方法;
- 枚举类 自动生成的
values()和valueOf()方法; - try-with-resources 语句生成的额外代码;
- lambda 表达式 和 方法引用 相关的生成类;
- 协变返回类型 桥接方法。
-
Class.instance.getName()- 返回 class 对象所表示的类型的名称字符串。其中每一维数组会用一个[表示。八个基本类型的数组由[+ 各自独立的大写字母 表示。类或接口的数组则由[L+classname+;表示。 -
Class.instance.getClassLoader()- 判断 class 对象所表示的类型的加载器。如果类型是原始类型或void,则返回null。 -
Class.instance.getTypeParameters()- 获取 class 对象所表示的类自身声明的泛型类型参数。对于原始类型或经过类型擦除的类,可能返回空数组。// 定义泛型类 class MyGenericClass<K, V> {} // ... // 获得 [K, V] MyGenericClass.class.getTypeParameters(); -
Class.instance.getSuperclass()- 获取 class 对象所表示的类的父类/超类。返回的是一个 Class 对象,但它不会包含泛型信息(即使父类是泛型类)。如果需要获取父类的泛型信息,请使用
Class.instance.getGenericSuperclass()。接口和基本类型的超类为
null。对于数组类型,始终返回Object.class。代理类(Proxy)的超类是Proxy.class。 -
Class.instance.getGenericSuperclass()- 获取 class 对象所表示的类的父类/超类。返回的是一个 Class 对象,如果父类是泛型类,则对象会包含泛型信息。 -
Class.instance.getPackage()- 获取 class 对象所表示的类的包路径。结果是一个字符串,格式为:package ${包路径}。 -
Class.instance.getInterfaces()- 获取 class 对象所表示的类直接实现的所有接口(即 不包括从父类继承的接口)。 -
Class.instance.getGenericInterfaces()- 获取 class 对象所表示的类直接实现的所有接口(即 不包括从父类继承的接口)。这些接口会保留泛型信息 -
Class.instance.getComponentType()- 获取 class 对象所表示的数组的类型。返回的是一个 Class 对象,对于非数组类型,则返回null。int[].class.getComponentType(); // 返回 int.class double[][].class.getComponentType(); // 返回 double[].class String[].class.getComponentType(); // 返回 String.class Object[][].class.getComponentType(); // 返回 Object[].class String.class.getComponentType(); // 返回 null -
Class.instance.getModifiers()- 获取 class 对象所表示的类/接口的修饰符。返回一个整数,结果是全部修饰符所代表的值的总和。修饰符 十六进制值 十进制值 public0x0001 1 private0x0002 2 protected0x0004 4 static0x0008 8 final0x0010 16 synchronized0x0020 32 volatile0x0040 64 transient0x0080 128 native0x0100 256 interface0x0200 512 abstract0x0400 1024 strictfp0x0800 2048 synthetic0x1000 4096 annotation0x2000 8192 enum0x4000 16384 由上表我们理解了,修饰符是以位掩码的形式存储的。
要解析所返回的整数值(即为了获取完整的修饰符字符串),可以使用
Modifier.toString(int mod)方法。要检查特定的修饰符,可以使用Modifier.isPublic(int mod)等方法。 -
Class.instance.getSigners()- 获取 class 对象所表示的(已签名)类的签名者信息。返回与类签名相关的对象数组(通常是CodeSigner或Certificate对象),主要用于 Java 安全机制中的类签名验证。 -
Class.instance.getEnclosingMethod()- 获取直接包含 class 对象所表示类的声明方法(如果该类是在方法中声明的局部类或匿名类)。返回的是一个方法对象。对于其他类型的类(如顶级类、静态嵌套类等),返回null。 -
Class.instance.getEnclosingConstructor()- 获取直接包含 class 对象所表示类的声明构造器(如果该类是在构造器中声明的局部类或匿名类)。对于其他类型的类则返回null。 -
Class.instance.getDeclaringClass()- 获取直接包含 class 对象所表示类的直接外层类(仅对成员类/接口/注解/枚举有效)。常用于检查一个类是否是另一个类的正式成员。 -
Class.instance.getEnclosingClass()- 获取词法上直接包含 class 对象所表示类的声明类(相比较于getDeclaringClass(),getEnclosingClass()适用于更多场景,包括局部类和匿名类)。常用于获取类定义的实际上下文环境。// 声明: class Outer { static class StaticNested {} // 静态成员类 void method() { class Local {} // 局部类 Runnable anon = new Runnable() {}; // 匿名类 } } // 测试: StaticNested.class.getDeclaringClass(); // 返回 Outer.class StaticNested.class.getEnclosingClass(); // 返回 Outer.class Local.class.getDeclaringClass(); // 返回 null Local.class.getEnclosingClass(); // 返回 Outer.class anon.getClass().getDeclaringClass(); // 返回 null anon.getClass().getEnclosingClass(); // 返回 Outer.class -
Class.instance.getSimpleName()- 获取 class 对象所表示的类的最简名称(不含包名和其他修饰信息):- 对于普通类:返回类名本身(不含包名)
- 对于嵌套类:返回嵌套类名(不含外部类名和包名)
- 对于数组:返回元素类型的简单名称加
[] - 对于匿名类:返回空字符串
"" - 对于基本类型:返回类型关键字,如
"int"
-
Class.instance.getTypeName()- 获取 class 对象所表示的类/接口的类型名称。- 对于普通类和接口:返回与
getCanonicalName()相同的结果(全限定名) - 对于数组类型:返回格式为
元素类型名 + []的字符串 - 对于基本类型:返回关键字名称,如
"int" - 对于匿名类/局部类:返回与
getName()相似的结果,如Main$1
- 对于普通类和接口:返回与
-
Class.instance.getCanonicalName()- 获取 class 对象所表示的类/接口的规范名称(完全限定类名)。- 对于普通类/接口:返回标准的全限定名,如
java.lang.String - 对于成员类/嵌套类:使用点
.分隔外部类和内部类,如java.util.Map.Entry - 对于数组:使用易读的
[]表示法,如java.lang.String[] - 对于基本类型:返回关键字名称,如
int - 对于匿名类/局部类:返回
null(因为它们没有规范名称)
- 对于普通类/接口:返回标准的全限定名,如
-
Class.instance.isAnonymousClass()- 获取 class 对象所表示的类是否为匿名类。 -
Class.instance.isLocalClass()- 获取 class 对象所表示的类是否为局部类(在方法内部定义的带名类)。 -
Class.instance.isMemberClass()- 获取 class 对象所表示的类是否为成员类。 -
Class.instance.getClasses()- 获取 class 对象所表示的类(及其从父类/接口继承)的公共成员类/公共成员接口。常用于扫描可用的公共成员类。返回一个 Class 对象数组:- 当前类中声明的所有 public 成员类和接口
- 从父类继承的所有 public 成员类和接口
- 从接口继承的所有 public 成员类和接口
请注意:匿名类不会出现在结果中。方法内定义的局部类不会包含在结果中。
-
Class.instance.getFields()- 获取 class 对象所表示的类/接口(及其从父类/接口继承)的所有公共字段。返回一个包含以下内容的 Field 对象数组:- 当前类/接口中声明的所有 public 字段
- 从父类继承的所有 public 字段
- 从接口继承的所有 public 字段
请注意:返回的字段顺序与声明顺序无关。
-
Class.instance.getMethods()- 获取 class 对象所表示的类/接口(及其从父类/接口继承)的所有公共方法。返回一个包含以下内容的 Method 对象数组:- 当前类/接口中声明的所有 public 方法
- 从父类继承的所有 public 方法
- 从接口继承的所有 public 方法
- 包括
Object类的公共方法
请注意:返回的方法顺序与声明顺序无关。
-
Class.instance.getConstructors()- 获取 class 对象所表示的类的所有公共构造函数。返回一个包含以下内容的 Constructor 对象数组:- 当前类/接口中声明的所有 public 构造函数
请注意:本方法不会返回父类的构造函数(构造函数也不能被继承)。
-
Class.instance.getField(String name)- 通过名称获取 class 对象所表示的类的特定公共字段(包括从父类和接口继承的公共字段)。如果子类和父类有同名字段,返回子类字段。 -
Class.instance.getMethod(String name, Class<?>... parameterTypes)- 通过方法名和参数类型获取 class 对象所表示的类的特定公共方法(包括从父类和接口继承的公共方法)。如果子类和父类有同名方法,返回子类方法。 -
Class.instance.getMethod(String name, Class<?>... parameterTypes)- 通过参数类型获取 class 对象所表示的类的特定公共构造函数。请注意:本方法不会返回父类的构造函数(构造函数也不能被继承)。
-
Class.instance.getDeclaredClasses()- 获取 class 对象所表示的类的成员类/公共成员接口。返回一个 Class 对象数组:- 当前类中声明的所有 成员类和接口,包括:静态成员类、非静态成员类、接口、注解、枚举
请注意:从父类继承的成员类、从接口继承的成员类、匿名类、局部类不会出现在结果中。
-
Class.instance.getDeclaredFields()- 获取 class 对象所表示的类的所有字段。返回一个 Field 对象数组:- 当前类中声明的所有 字段,但不包括从父类或接口继承的字段
-
Class.instance.getDeclaredMethods()- 获取 class 对象所表示的类的所有方法。返回一个 Method 对象数组:- 当前类中声明的所有 方法,但不包括从父类或接口继承的方法
-
Class.instance.getDeclaredConstructors()- 获取 class 对象所表示的类的所有构造函数。返回一个Constructor<?>对象数组:- 当前类中声明的所有 构造函数,但不包括父类的构造函数(因为构造函数不能被继承)
-
Class.instance.getDeclaredField(String name)- 通过名称获取 class 对象所表示的类的特定字段。 -
Class.instance.getDeclaredMethod(String name, Class<?>... parameterTypes)- 通过名称和参数类型获取 class 对象所表示的类的特定方法。 -
Class.instance.getDeclaredConstructor(Class<?>... parameterTypes)- 通过参数类型获取 class 对象所表示的类的特定构造函数。 -
Class.instance.getResourceAsStream(String name)- 通过名称加载与 class 对象所表示的类位于相同位置的资源文件。返回可用于读取资源的InputStream(资源不存在时则返回null)。路析规则:路径格式 查找位置 "filename"与类同包下的资源(如 com/example/MyClass.class→com/example/filename)"/filename"类路径根目录下的资源,即绝对路径(推荐使用) "subdir/filename"类所在包下的子目录资源 请注意:
- 确认资源文件已正确打包到 JAR/WAR 中
- 资源找不到时,检查模块的
module-info.java是否开放了资源包 - 在 Windows 系统中仍使用
/作为分隔符 - 确保及时关闭
InputStream - 最好使用
try-with-resources语法
-
Class.instance.getResource(String name)- 通过名称获取与 class 对象所表示的类位于相同位置的资源文件的 URL 引用。返回一个java.net.URL对象。常用于获取资源精确位置或资源的 URL 特性(如获取协议、主机等信息)。URL jarResource = MyClass.class.getResource("/assets/images/logo.jpg"); // 可能返回:jar:file:/path/to/app.jar!/assets/images/logo.jpg -
Class.instance.getProtectionDomain()- 获取 class 对象所表示的类的保护域(ProtectionDomain)信息。返回一个java.security.ProtectionDomain对象。该对象包括:- 代码来源(CodeSource):类文件的来源位置(一个 URL)和证书
- 权限集合(Permissions):该类被授予的所有权限
- 类加载器(ClassLoader):加载该类的类加载器
- 主体(Principals):关联的安全主体(Java 2 安全模型)
-
Class.instance.desiredAssertionStatus()- 检查 class 对象所表示的类是否应该启用断言功能。返回一个布尔值。断言状态由以下因素决定:-
JVM 启动参数:
-ea或-enableassertions:启用断言-da或-disableassertions:禁用断言,默认值- 可针对特定包或类设置(如
-ea:com.example...)
-
类加载器默认状态:
- 可通过
ClassLoader.setDefaultAssertionStatus()设置,用于设置默认断言状态
- 可通过
-
包默认状态:
- 可通过
ClassLoader.setPackageAssertionStatus()设置,用于设置整个包的断言状态
- 可通过
-
-
Class.instance.isEnum()- 检查 class 对象所表示的类是否为枚举类型。返回一个布尔值。对于数组和基本类型总是返回false。 -
Class.instance.getEnumConstants()- 获取 class 对象所表示的枚举类的所有常量值(所返回数组中的元素顺序与声明顺序一致),返回类型与枚举类型匹配。对于非枚举类型,则返回null。 -
Class.instance.cast(Object obj)- 将对象安全地转换为 class 对象所表示的类或接口类型。返回一个类或接口对象(前提是obj为null或可以转换为Class对象表示的类型),否则抛出类转换异常。与强制类型转换相比,本方法的最大优点是保留了泛型,而前者会出现类型擦除。
-
Class.instance.asSubclass(Class<U> clazz)- 将 clazz 类对象安全地转换为 class 对象所表示的类的子类,返回一个Class对象。// 插件加载框架中的类型验证 public <T> T loadPlugin(String className, Class<T> pluginBaseClass) throws Exception { // 加载类 Class<?> loadedClass = Class.forName(className); // 验证是否为要求的基类/接口的子类 Class<? extends T> pluginClass = loadedClass.asSubclass(pluginBaseClass); // 创建实例 return pluginClass.getConstructor().newInstance(); } // 使用示例 Runnable plugin = loadPlugin("com.example.MyPlugin", Runnable.class); -
Class.instance.getAnnotation(Class<A> annotationClass)- 获取 class 对象所表示的类上指定类型的注解(包括继承了父类和接口的注解,只要这注解声明了@Inherited元注解)。返回一个注解对象,如果不存在则返回null。// 实现一个通用的注解处理器 public void processAnnotations(Class<?> clazz) { // 检查是否标记了弃用注解 Deprecated deprecated = clazz.getAnnotation(Deprecated.class); if (deprecated != null) { System.out.println("警告: " + clazz.getName() + " 已弃用"); } // 处理自定义注解 Service serviceAnno = clazz.getAnnotation(Service.class); if (serviceAnno != null) { registerService(clazz, serviceAnno.value()); } } -
Class.instance.isAnnotationPresent(Class<? extends Annotation> annotationClass)- 判断 class 对象所表示的类是否标记了特定注解(不包括元注解)。 -
Class.instance.getAnnotationsByType(Class<A> annotationClass)- 处理标记 class 对象所表示的类上的 可重复注解(@Repeatable)。返回注解实例数组(没有相关注解则返回空数组)。如果父类或接口的可重复注解标记了@Inherited元注解,那么被继承的这些注解也会被处理并返回。 -
Class.instance.getAnnotations()- 获取 class 对象所表示的类上的全部注解(包括继承了父类和接口的注解,只要这些注解声明了@Inherited元注解)。// 注解处理器框架中的通用处理 public void processClassAnnotations(Class<?> clazz) { for (Annotation ann : clazz.getAnnotations()) { if (ann instanceof Service) { registerService(clazz); continue; } if (ann instanceof Component) { registerComponent(clazz); continue; } // 可以继续处理其他注解类型... } } -
Class.instance.getDeclaredAnnotation(Class<A> annotationClass)- 获取 class 对象所表示的类上指定类型的注解(不包括继承了父类和接口的注解)。返回一个注解对象,如果不存在则返回null。 -
Class.instance.getDeclaredAnnotationsByType(Class<A> annotationClass)- 用于处理标记 class 对象所表示的类上的 可重复注解(@Repeatable)。返回注解实例数组(没有相关注解则返回空数组)。不包括继承父类或接口的可重复注解。 -
Class.instance.getDeclaredAnnotations()- 获取 class 对象所表示的类上的全部注解(不包括继承父类和接口的注解)。 -
Class.instance.getAnnotatedSuperclass()- 获取 class 对象所表示的类的父类的注解。返回一个AnnotatedType对象,可通过该对象的getAnnotations()方法获取注解对象列表。获取的内容包括:- 父类声明处的类型注解,如
@Deprecated - 泛型参数上的类型注解,如
@NotNull - 完整的泛型类型信息
- 父类声明处的类型注解,如
-
Class.instance.getAnnotatedInterfaces()- 获取 class 对象所表示的类所实现接口的注解。返回一个AnnotatedType数组(每个元素表示一个接口的注解信息),可通过元素对象的getAnnotations()方法获取注解对象列表。
小结
本文对 Class.java 做一点点浅层分析,对于刚入门的同学来说,这足以让大家理解很多框架(如 Spring)的思想了。掌握 Class 类是理解 Java 反射的前提。下这点功夫,是很值得的。