Java反射

1,400 阅读5分钟

Java反射

官方文档

docs.oracle.com/javase/tuto…

Java的作用

反射通常由程序使用,这些程序需要能够检查或修改在Java虚拟机中运行的应用程序的运行时行为,这是一个相对高级的功能,只有那些掌握了语言基础知识的开发人员才能使用。考虑到这一点,反射是一种强大的技术,可以使应用程序执行本来不可能的操作。

1. 可扩展性

应用程序可以通过使用完全限定名称创建可扩展性对象的实例来使用外部的用户定义类。

2. 类浏览器和可视化开发环境

类浏览器需要能够枚举类的成员。可视化开发环境可以从利用反射中可用的类型信息中受益,以帮助开发人员编写正确的代码。

3. 调试器和测试工具

调试器需要能够检查类上的私有成员。测试工具可以利用反射系统地调用类上定义的可发现的set API,以确保测试套件中的高级代码覆盖率。

反射的缺点

反射是强大的,但不应随意使用。如果可以在不使用反射的情况下执行操作,则优选避免使用它。通过反射访问代码时,应牢记以下问题。

1. 绩效开销

由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。因此,反射操作的性能低于非反射操作,并且应避免在性能敏感应用程序中频繁调用的代码段中。

2. 安全限制

反射需要运行时权限,在安全管理器下运行时可能不存在。对于必须在受限安全上下文中运行的代码,例如在Applet中,这是一个重要的考虑因素。

3. 内部接触

由于反射允许代码执行在非反射代码中非法的操作,例如访问private字段和方法,因此使用反射会导致意外的副作用,这可能导致代码功能失常并可能破坏可移植性。反射代码打破了抽象,因此可能会通过升级平台来改变行为。

类反射方法

获取Class对象

Object.getClass()

.class语法

原始类型不能使用Object.getClass()方法获得Class对象

Class.forName()

如果可以得到类的全称可以使用该方法获取Class对象

基本类型的包装类TYPE静态变量

其他返回Class对象的方法

  1. Class.getSuperclass()
  2. Class.getClasses() 返回作为类成员的所有公共类,接口和枚举,包括继承的成员。
  3. Class.getDeclaredClasses() 返回在此类中显式声明的所有类接口和枚举。
  4. Class.getDeclaringClass() 返回在此类成员变量声明的类,匿名类没有DeclaringClass,但是有EnclosingClass
  5. java.lang.reflect.Field.getDeclaringClass()
  6. java.lang.reflect.Method.getDeclaringClass()
  7. java.lang.reflect.Constructor.getDeclaringClass()
  8. Class.getEnclosingClass() 返回类的直接封闭类。

检查类修饰符和类型

Class.getModifiers()方法获取修饰符和类型 可以使用一个或多个影响其运行时行为的修饰符声明一个类:

  1. public, protected, and private
  2. abstract
  3. static
  4. final
  5. strictfp
  6. Annotations

获取类的成员

获取成员变量

Class API 列表返回值? 继承成员? 私有成员?
getDeclaredField() no no yes
getField() no yes no
getDeclaredFields() yes no yes
getFields() yes yes no

获取成员方法

Class API 列表返回值? 继承方法? 私有方法?
getDeclaredMethod() no no yes
getMethod() no yes no
getDeclaredMethods() yes no yes
getMethods() yes yes no

构造方法

Class API 列表返回值? 继承方法? 私有方法?
getDeclaredConstructor() no N/A1 yes
getConstructor() no N/A1 no
getDeclaredConstructors() yes N/A1 yes
getConstructors() yes N/A1 no

故障排除

  1. 警告报错:Compiler Warning: "Note: ... uses unchecked or unsafe operations"
  2. 构造函数不可访问时的InstantiationException

成员

Fields

获取字段类型

  • Field.getType():获取字段的类型
  • Field.getGenericType():获取字段的泛型类型

检索和解析字段修饰符

  • Field.getModifiers():获取字段修饰符
  • Field.isSynthetic():判断字段是否为合成的
  • Field.isEnumConstant():判断字段是否为枚举

获取和设置字段值

  • Field.set*() :获取字段值
  • Field.get*() :设置字段值

故障排除

  1. IllegalArgumentException due to Inconvertible Types
  2. NoSuchFieldException for Non-Public Fields
  3. IllegalAccessException when Modifying Final Fields

Methods

获取方法类型信息

  • Method.toGenericString()
  • Method.getReturnType()
  • Method.getGenericReturnType()
  • Method.getParameterTypes()
  • Method.getGenericParameterTypes()
  • Method.getExceptionTypes()
  • Method.getGenericExceptionTypes()

获取方法参数的名字

  • Method.getParameters():获取方法参数
  • Parameter.getType():获取参数类型
  • Parameter.getName():获取参数名称
  • Parameter.Modifiers():获取参数修饰符
  • Parameter.isImplicit():true如果在源代码中隐式声明此参数
  • Parameter.isNamePresent():true如果参数根据.class文件具有名称
  • Parameter.isSynthetic():true如果在源代码中既未隐式声明也未显式声明此参数

检索和解析方法修饰符

  • Method.getModifiers():获取方法修饰符
  • Method.isSynthetic():返回true此可执行文件是否为合成构造
  • Method.isVarArgs():返回true如果这个可执行文件被宣布为带有可变数量的参数
  • Method.isBridge():true如果此方法是桥接方法

调用方法

  • Method.invoke():调用方法

故障排除

  1. NoSuchMethodException Due to Type Erasure
  2. IllegalAccessException when Invoking a Method
  3. IllegalArgumentException from Method.invoke()
  4. InvocationTargetException when Invoked Method Fails

Constructors

获取构造函数

检索和解析构造函数修饰符

  • Constructor.getModifiers()

创建一个新实例

  • Constructor.newInstance():优先使用
  • Class.newInstance()

故障排除

  1. InstantiationException Due to Missing Zero-Argument Constructor
  2. Class.newInstance() Throws Unexpected Exception
  3. Problems Locating or Invoking the Correct Constructor
  4. IllegalAccessException When Attempting to Invoke an Inaccessible Constructor

数组和枚举类型

数组

识别数组类型

  • Class.isArray()

创建新数组

  • Array.newInstance()

获取和设置数组及其组件

  • Array.set*()
  • Array.get()

故障排除

  1. IllegalArgumentException due to Inconvertible Types
  2. ArrayIndexOutOfBoundsException for Empty Arrays
  3. IllegalArgumentException if Narrowing is Attempted

枚举

识别枚举类型

  • Class.isEnum():枚举无法通过反射实例化,枚举常量是唯一的
  • Class.getEnumConstants()
  • Field.isEnumConstant()

使用枚举类型获取和设置字段

  • Field.set()
  • Field.get()

故障排除

  1. IllegalArgumentException When Attempting to Instantiate an Enum Type
  2. IllegalArgumentException when Setting a Field with an Incompatible Enum Type