文档

Java™ 教程
隐藏目录
检查类修饰符和类型
指南:反射 API
课程:

检查类的修饰符和类型

一个类可以声明一个或多个修饰符,这些修饰符会影响它的运行时行为:

并非所有的修饰符都可以应用于所有的类,例如接口不能是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("类:%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虚拟机定义的。特别是,数组实现了Cloneablejava.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.RetentionPolicyRUNTIME的注解才可以访问。在语言中预定义的三个注解@Deprecated@Override@SuppressWarnings中,只有@Deprecated可以在运行时获得。

上一页:检索类对象
下一页:查找类成员