Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
可以使用一个或多个影响其运行时行为的修饰符声明一个类:
public
,protected
和 private
abstract
static
final
strictfp
并非所有类都允许使用所有修饰符,例如,接口不能是 final
,并且枚举不能是 abstract
。java.lang.reflect.Modifier
包含所有可能修饰符的声明。它还包含可用于解码由 Class.getModifiers()
返回的修饰符集的方法。
示例显示了如何获取类的声明组件,包括修饰符,泛型类型形参,实现的接口和继承路径。由于 ClassDeclarationSpy
Class
实现 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("Class:%n %s%n%n", c.getCanonicalName()); out.format("Modifiers:%n %s%n%n", Modifier.toString(c.getModifiers())); out.format("Type Parameters:%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(" -- No Type Parameters --%n%n"); } out.format("Implemented Interfaces:%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(" -- No Implemented Interfaces --%n%n"); } out.format("Inheritance Path:%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(" -- No Super Classes --%n%n"); } out.format("Annotations:%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(" -- No Annotations --%n%n"); } // production code should handle this exception more gracefully } 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 Class: java.util.concurrent.ConcurrentNavigableMap Modifiers: public abstract interface Type Parameters: K V Implemented Interfaces: java.util.concurrent.ConcurrentMap<K, V> java.util.NavigableMap<K, V> Inheritance Path: -- No Super Classes -- Annotations: -- No Annotations --
这是源代码中 java.util.concurrent.ConcurrentNavigableMap
的实际声明:
public interface ConcurrentNavigableMap<K,V> extends ConcurrentMap<K,V>, NavigableMap<K,V>
abstract
。编译器为每个接口添加此修饰符。此外,此声明包含两个泛型类型形参,K
和 V
。示例代码只是打印这些参数的名称,但是可以使用 java.lang.reflect.TypeVariable
中的方法获取有关它们的其他信息。接口还可以实现如上所示的其他接口。
$ java ClassDeclarationSpy "[Ljava.lang.String;" Class: java.lang.String[] Modifiers: public abstract final Type Parameters: -- No Type Parameters -- Implemented Interfaces: interface java.lang.Cloneable interface java.io.Serializable Inheritance Path: java.lang.Object Annotations: -- No Annotations --
由于数组是运行时对象,因此所有类型信息都由 Java 虚拟机定义。特别是,数组实现 Cloneable
和 java.io.Serializable
,它们的直接超类总是 Object
。
$ java ClassDeclarationSpy java.io.InterruptedIOException Class: java.io.InterruptedIOException Modifiers: public Type Parameters: -- No Type Parameters -- Implemented Interfaces: -- No Implemented Interfaces -- Inheritance Path: java.io.IOException java.lang.Exception java.lang.Throwable java.lang.Object Annotations: -- No Annotations --
从继承路径可以推断,java.io.InterruptedIOException
是一个检查型异常,因为 RuntimeException
不存在(译注:指未继承 RuntimeException,RuntimeException 和 Error 是非检查型异常)。
$ java ClassDeclarationSpy java.security.Identity Class: java.security.Identity Modifiers: public abstract Type Parameters: -- No Type Parameters -- Implemented Interfaces: interface java.security.Principal interface java.io.Serializable Inheritance Path: java.lang.Object Annotations: @java.lang.Deprecated()
此输出显示 java.security.Identity
,一个已弃用的 API,拥有注解 java.lang.Deprecated
。反射代码可以使用它来检测已弃用的 API。
java.lang.annotation.RetentionPolicy
为 RUNTIME
的才可以访问。在语言中预先定义的三个注解中, @Deprecated
,@Override
和 @SuppressWarnings
,只有 @Deprecated
在运行时可用。