[关闭]
@wangwangheng 2014-12-09T13:57:54.000000Z 字数 3974 阅读 1955

反射

Java


仅有一个大致的介绍,具体的可以参考官方文档中反射相关的内容

1. Class描述

1.1 继承结构

  1. public final class Class<T>
  2. extends Object
  3. implements Serializable, GenericDeclaration, Type, AnnotatedElement

1.2 描述

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

2. 得到类的字节码的三种方式

2.1 通过Object的getClass()方法得到

  1. Person person = new Person();
  2. Class<?> objectClass = person.getClass();

2.2 通过类名.class的方式I的到

  1. Class<?> clazzClass = Person.class;

2.3 通过Class.forName()静态方法得到(注意会抛出异常;参数必须是类全名)

  1. try {
  2. Class<?> fornameClass = Class.forName("com.xinye.text.Person");
  3. } catch (ClassNotFoundException e) {
  4. e.printStackTrace();
  5. }

3. 得到类中的方法

可以通过Class类中定义的功能来完成。并且类中的所有内容都被封装成了对象。

3.1 得到类中的定义的以及父类中定义的public成员方法

3.1.1 getMethods()

返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

3.1.2 getMethod(String name,Class... parameterTypes)

返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

name 参数是一个 String,用于指定所需方法的简称。

parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果parameterTypes 为 null,则按空数组处理。

如果 name 是 "<init>;" 或 "<clinit>",则将引发 NoSuchMethodException。否则,要反映的方法由下面的算法确定(设 C 为此对象所表示的类):

  1. 在 C 中搜索任一匹配的方法。如果找不到匹配的方法,则将在 C 的超类上递归调用第 1 步算法。
  2. 如果在第 1 步中没有找到任何方法,则在 C 的超接口中搜索匹配的方法。如果找到了这样的方法,则返回该方法。

在 C 类中查找匹配的方法:如果 C 正好声明了一个具有指定名称的公共方法并且恰恰有相同的形参类型,则它就是返回的方法。

如果在 C 中找到了多个这样的方法,并且其中有一个方法的返回类型比其他方法的返回类型都特殊,则反映该方法;否则将从中任选一个方法。

注意,类中可以有多个匹配方法,因为尽管 Java 语言禁止类声明带有相同签名但不同返回类型的多个方法,但 Java 虚拟机并不禁止。这增加了虚拟机的灵活性,可以用来实现各种语言特性。例如,可以使用桥方法 (brige method)实现协变返回;桥方法以及将被重写的方法将具有相同的签名,不同的返回类型。

3.2 得到类中定义的方法,包括私有方法,但是不包括父类中定义的方法

3.2.1 getDeclareMethods()

返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

3.2.2 getDeclaredMethod(String name,Class... parameterTypes)

返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

name 参数是一个 String,它指定所需方法的简称,
parameterTypes 参数是 Class 对象的一个数组,它按声明顺序标识该方法的形参类型。

如果在某个类中声明了带有相同参数类型的多个方法,并且其中有一个方法的返回类型比其他方法的返回类型都特殊,则返回该方法;否则将从中任选一个方法。如果名称是 "<init>" 或 "<clinit>>",则引发一个 NoSuchMethodException。

3.3 得到类中的构造方法

3.3.1 getConstructors()

返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

3.3.2 getConstructor(Class... parameterTypes)

返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声明顺序标识构造方法的形参类型。

如果此 Class 对象表示非静态上下文中声明的内部类,则形参类型作为第一个参数包括显示封闭的实例。

要返回的构造方法是此 Class 对象所表示的类的公共构造方法,其形参类型与 parameterTypes 所指定的参数类型相匹配。

4. 通过字节码得到类的实例

4.1 newInstance()

创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。

注意,此方法传播 null 构造方法所抛出的任何异常,包括已检查的异常。使用此方法可以有效地绕过编译时的异常检查,而在其他情况下编译器都会执行该检查。 Constructor.newInstance 方法将该构造方法所抛出的任何异常包装在一个(已检查的)InvocationTargetException 中,从而避免了这一问题。

IllegalAccessException - 如果该类或其 null 构造方法是不可访问的。

InstantiationException - 如果此 Class 表示一个抽象类、接口、数组类、基本类型或 void; 或者该类没有 null 构造方法; 或者由于其他某种原因导致实例化失败。

ExceptionInInitializerError - 如果该方法引发的初始化失败。

SecurityException - 如果存在安全管理器 s,并满足下列任一条件:

  • 调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝创建该类的新实例
  • 调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包

4.2 通过调用指定的构造函数来实例化

5. 调用方法

  1. Class<Person> clazzClass = Person.class;
  2. Person p = clazzClass.newInstance();
  3. // 得到指定参数列表的方法
  4. Method m = clazzClass.getMethod("setName", String.class);
  5. // 调用方法
  6. m.invoke(p, "张三heheh");
  7. System.out.println(p);
  8. // 得到没有参数列表的方法;如果是私有的,可以设置访问性为true
  9. Method m2 = clazzClass.getDeclaredMethod("systemOut");
  10. System.out.println("before - m2 accessible::" + m2.isAccessible());
  11. // 设置访问性为true
  12. m2.setAccessible(true);
  13. System.out.println("after - m2 accessible::" + m2.isAccessible());
  14. // 调用方法
  15. m2.invoke(p);

6. 得到

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注