检查类修饰符和类型
可以使用一个或多个影响其运行时行为的修饰符来声明一个类:
-
访问修饰符:
public
,protected
和private
-
需要覆盖的修饰符:
abstract
-
修饰符仅限一个实例:
static
-
禁止修改值的修饰符:
final
-
修饰符强制严格的浮点行为:
strictfp
-
Annotations
并非所有类都允许使用所有修饰符,例如,interface不能为final
,而枚举不能为abstract
。 java.lang.reflect.Modifier包含所有可能的修饰符的声明。它还包含可用于解码Class.getModifiers()返回的修饰符集的方法。
ClassDeclarationSpy示例演示如何获取类的声明组件,包括修饰符,泛型类型参数,已实现的interface和继承路径。由于Class实现了java.lang.reflect.AnnotatedElementinterface,因此还可以查询运行时注解。
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);
}
}
}
以下是输出的一些 samples。用户 Importing 以斜体显示。
$ 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>
请注意,由于这是一个interface,因此隐式为abstract
。编译器为每个interface添加此修饰符。另外,此声明包含两个泛型参数K
和V
。该示例代码仅打印这些参数的名称,但是可以使用java.lang.reflect.TypeVariable中的方法检索有关它们的其他信息。interface也可以实现其他interface,如上所示。
$ 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不存在。
$ 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。
Note:
并非所有 注解 都可以通过反射获得。只能访问java.lang.annotation.RetentionPolicy等于RUNTIME的那些。在语言@Deprecated,@Override和@SuppressWarnings中 预定义的三个 注解 中,只有@Deprecated在运行时可用。