此 Java 教程是为 JDK 8 编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java 语言更改以了解 Java SE 9 及后续版本中更新的语言特性的摘要。
请参阅JDK 发行说明以获取有关所有 JDK 发行版本的新功能、增强功能以及已删除或不推荐使用的选项的信息。
一个类可以声明一个或多个修饰符,这些修饰符会影响它的运行时行为:
并非所有的修饰符都可以应用于所有的类,例如接口不能是final,枚举不能是abstract。java.lang.reflect.Modifier 包含了所有可能的修饰符声明。它还包含了一些方法,可以用于解码由 Class.getModifiers() 返回的修饰符集合。
示例 展示了如何获取类的声明组件,包括修饰符、泛型类型参数、实现的接口和继承路径。由于 ClassDeclarationSpyClass 实现了 java.lang.reflect.AnnotatedElement 接口,因此也可以查询运行时的注解。
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;
public class ClassDeclarationSpy {
public static void main(String... args) {
try {
Class<?> c = Class.forName(args[0]);
out.format("类:%n %s%n%n", c.getCanonicalName());
out.format("修饰符:%n %s%n%n",
Modifier.toString(c.getModifiers()));
out.format("类型参数:%n");
TypeVariable[] tv = c.getTypeParameters();
if (tv.length != 0) {
out.format(" ");
for (TypeVariable t : tv)
out.format("%s ", t.getName());
out.format("%n%n");
} else {
out.format(" -- 没有类型参数 --%n%n");
}
out.format("实现的接口:%n");
Type[] intfs = c.getGenericInterfaces();
if (intfs.length != 0) {
for (Type intf : intfs)
out.format(" %s%n", intf.toString());
out.format("%n");
} else {
out.format(" -- 没有实现的接口 --%n%n");
}
out.format("继承路径:%n");
List<Class> l = new ArrayList<Class>();
printAncestor(c, l);
if (l.size() != 0) {
for (Class<?> cl : l)
out.format(" %s%n", cl.getCanonicalName());
out.format("%n");
} else {
out.format(" -- 没有父类 --%n%n");
}
out.format("注解:%n");
Annotation[] ann = c.getAnnotations();
if (ann.length != 0) {
for (Annotation a : ann)
out.format(" %s%n", a.toString());
out.format("%n");
} else {
out.format(" -- 没有注解 --%n%n");
}
// 实际的代码中应该更优雅地处理这个异常
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
private static void printAncestor(Class<?> c, List<Class> l) {
Class<?> ancestor = c.getSuperclass();
if (ancestor != null) {
l.add(ancestor);
printAncestor(ancestor, l);
}
}
}
以下是一些输出的示例。用户输入以斜体显示。
$ java ClassDeclarationSpy java.util.concurrent.ConcurrentNavigableMap 类: java.util.concurrent.ConcurrentNavigableMap 修饰符: public abstract interface 类型参数: K V 实现的接口: java.util.concurrent.ConcurrentMap<K, V> java.util.NavigableMap<K, V> 继承路径: -- 没有父类 -- 注解: -- 没有注解 --
这是源代码中 java.util.concurrent.ConcurrentNavigableMap 的实际声明:
public interface ConcurrentNavigableMap<K,V>
extends ConcurrentMap<K,V>, NavigableMap<K,V>
abstractKVjava.lang.reflect.TypeVariable
$ java ClassDeclarationSpy "[Ljava.lang.String;" 类: java.lang.String[] 修饰符: 公共的 抽象的 最终的 类型参数: -- 没有类型参数 -- 实现的接口: 接口 java.lang.Cloneable 接口 java.io.Serializable 继承路径: java.lang.Object 注解: -- 没有注解 --
由于数组是运行时对象,所有的类型信息都是由Java虚拟机定义的。特别是,数组实现了Cloneable和java.io.Serializable接口,并且它们的直接超类始终是Object。
$ java ClassDeclarationSpy java.io.InterruptedIOException 类: java.io.InterruptedIOException 修饰符: 公共的 类型参数: -- 没有类型参数 -- 实现的接口: -- 没有实现的接口 -- 继承路径: java.io.IOException java.lang.Exception java.lang.Throwable java.lang.Object 注解: -- 没有注解 --
根据继承路径,可以推断出java.io.InterruptedIOException是一个已检查的异常,因为RuntimeException不存在。
$ java ClassDeclarationSpy java.security.Identity 类: java.security.Identity 修饰符: 公共的 抽象的 类型参数: -- 没有类型参数 -- 实现的接口: 接口 java.security.Principal 接口 java.io.Serializable 继承路径: java.lang.Object 注解: @java.lang.Deprecated()
该输出显示java.security.Identity是一个已废弃的API,并具有注解java.lang.Deprecated。这可以被反射代码用于检测已废弃的API。
java.lang.annotation.RetentionPolicy为RUNTIME的注解才可以访问。在语言中预定义的三个注解@Deprecated、@Override和@SuppressWarnings中,只有@Deprecated可以在运行时获得。