java之反射
java之反射
反射
Uses of Reflection
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.
- Extensibility FeaturesAn application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.
- Class Browsers and Visual Development EnvironmentsA class browser needs to be able to enumerate the members of classes. Visual development environments can benefit from making use of type information available in reflection to aid the developer in writing correct code.
- Debuggers and Test ToolsDebuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.
反射主要使用场景:
- 根据类名创建对象
- Method.invoke
运行过程中动态加载类,创建对象,方法调用。
反射的应用场景
反射的主要应用场景有:
- 开发通用框架 - 反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 JavaBean、Filter 等),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。
- 动态代理 - 在切面编程(AOP)中,需要拦截特定的方法,通常,会选择动态代理方式。这时,就需要反射技术来实现了。
- 注解 - 注解本身仅仅是起到标记作用,它需要利用反射机制,根据注解标记去调用注解解释器,执行行为。如果没有反射机制,注解并不比注释更有用。
- 可扩展性功能 - 应用程序可以通过使用完全限定名称创建可扩展性对象实例来使用外部的用户定义类。
反射的缺点
- 性能开销 - 由于反射涉及动态解析的类型,因此无法执行某些 Java 虚拟机优化。因此,反射操作的性能要比非反射操作的性能要差,应该在性能敏感的应用程序中频繁调用的代码段中避免。
- 破坏封装性 - 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
- 内部曝光 - 由于反射允许代码执行在非反射代码中非法的操作,例如访问私有字段和方法,所以反射的使用可能会导致意想不到的副作用,这可能会导致代码功能失常并可能破坏可移植性。反射代码打破了抽象,因此可能会随着平台的升级而改变行为。
使用
java.lang.reflect 包的核心接口和类如下:
- Member 接口 - 反映关于单个成员(字段或方法)或构造函数的标识信息。
- Field 类 - 提供一个类的域的信息以及访问类的域的接口。
- Method 类 - 提供一个类的方法的信息以及访问类的方法的接口。
- Constructor 类 - 提供一个类的构造函数的信息以及访问类的构造函数的接口。
- Array 类 - 该类提供动态地生成和访问 JAVA 数组的方法。
- Modifier 类 - 提供了 static 方法和常量,对类和成员访问修饰符进行解码。
- Proxy 类 - 提供动态地生成代理类和类实例的静态方法。
获得Class 对象
要想使用反射,首先需要获得待操作的类所对应的 Class 对象
- 使用 Class 类的 forName 静态方法
- 直接获取某一个对象的 class
- 调用 Object 的 getClass 方法,示例:
创建实例
- 用 Class 对象的 newInstance 方法。
- 用 Constructor 对象的 newInstance 方法。
field
- getFiled - 根据名称获取公有的(public)类成员。
- getDeclaredField - 根据名称获取已声明的类成员。但不能得到其父类的类成员。
- getFields - 获取所有公有的(public)类成员。
- getDeclaredFields - 获取所有已声明的类成员。
Method
- getMethod - 返回类或接口的特定方法。其中第一个参数为方法名称,后面的参数为方法参数对应 Class 的对象。
- getDeclaredMethod - 返回类或接口的特定声明方法。其中第一个参数为方法名称,后面的参数为方法参数对应 Class 的对象。
- getMethods - 返回类或接口的所有 public 方法,包括其父类的 public 方法。
- getDeclaredMethods - 返回类或接口声明的所有方法,包括 public、protected、默认(包)访问和 private 方法,但不包括继承的方法。
获取一个 Method 对象后,可以用 invoke 方法来调用这个方法。
Constructor
- getConstructor - 返回类的特定 public 构造方法。参数为方法参数对应 Class 的对象。
- getDeclaredConstructor - 返回类的特定构造方法。参数为方法参数对应 Class 的对象。
- getConstructors - 返回类的所有 public 构造方法。
- getDeclaredConstructors - 返回类的所有构造方法。
获取一个 Constructor 对象后,可以用 newInstance 方法来创建类实例。
https://zhuanlan.zhihu.com/p/60805342