JAVA反射,反射机制

我会带着你远行 2024-03-30 10:25 146阅读 0赞

文章目录

  • 一、反射是什么?
    • 定义
    • 用途
  • 二、反射的原理
  • 三、反射的优缺点
  • 四、反射机制的相关类
    • Class类
    • Field类
    • Method类
    • Constructor类
    • 获取Class类对象的三种方法
    • 反射常用类和方法
  • 总结

一、反射是什么?

定义

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

用途

  1. 通过反射,Java 代码可以发现有关已加载类的字段,方法和构造函数的信息,并可以在安全限制内对这些字段,方法和构造函数进行操作。
  2. 很多人都认为反射在实际Java中开发应用中并不广泛,其实不然。当我们在使用 IDE(如 IDEA/Eclipse)时,当我们输入一个对象或者类并调用它的属性和方法时,一按 (“.”)点号,编译器就会自动列出她的属性或方法,这里就会用到反射。
  3. 反射最重要的用途就是开发各种通用框架
    很多框架(比如 Spring)都是配置化的(比如Spring 通过 XML 配置模式装载 Bean),为了保证框架的通用性,他们可能根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射了,运行时动态加载需要加载的对象。

对于框架开发人员来说,反射作用非常大,它是各种容器实现的核心。而对于一般的开发者来说,不深入框架开发反射用的就会少一点,不过了解一下框架的底层机制有助于丰富自己的编程思想,也是很有益的。

  • Java反射框架提供以下功能:

    • 在运行时判定任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判定任意一个类所具有的成员变量和方法
    • 在运行时调用任意一个对象的方法

比如,加载数据库驱动的,用到的也是反射。

  1. Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动

二、反射的原理

下图是类的正常加载过程、反射原理与class对象:
Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。
Java的反射

三、反射的优缺点

  • 优点:

    • 在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
    • 使用反射机制,代码可以在运行时装配,提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需硬编码目标类
  • 缺点:

    • 性能问题:使用反射基本上是一种解释操作,JVM无法对这些代码进行优化,因此,反射操作的效率要比那些非反射操作低得多。反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,对性能要求高的程序中不建议使用
    • 安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行
    • 内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用——代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

四、反射机制的相关类

Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;






























类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法
Modifier类 提供了static方法和常量,对类和成员访问修饰符进行解码。

Class类

Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。

  • 获取类相关的方法
    class
  • 获得类中属性相关的方法

























方法 用途
getField(String name) 获得某个公有的属性对象
getFields() 获得所有公有的属性对象
getDeclaredField(String name) 获得某个属性对象
getDeclaredFields() 获得所有属性对象
  • 获得类中注解相关的方法

























方法 用途
getAnnotation(Class annotationClass) 返回该类中与参数类型匹配的公有注解对象
getAnnotations() 返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass) 返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations() 返回该类所有的注解对象
  • 获得类中构造器相关的方法

























方法 用途
getConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法
getConstructors() 获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的构造方法
getDeclaredConstructors() 获得该类所有构造方法
  • 获得类中方法相关的方法

























方法 用途
getMethod(String name, Class…<?> parameterTypes) 获得该类某个公有的方法
getMethods() 获得该类所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes) 获得该类某个方法
getDeclaredMethods() 获得该类所有方法
  • 类中其他重要的方法













































方法 用途
isAnnotation() 如果是注解类型则返回true
isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果是指定类型注解类型则返回true
isAnonymousClass() 如果是匿名类则返回true
isArray() 如果是一个数组类则返回true
isEnum() 如果是枚举类则返回true
isInstance(Object obj) 如果obj是该类的实例则返回true
isInterface() 如果是接口类则返回true
isLocalClass() 如果是局部类则返回true
isMemberClass() 如果是内部类则返回true

Field类

Field代表类的成员变量(成员变量也称为类的属性)。






















方法 用途
equals(Object obj) 属性与obj相等则返回true
get(Object obj) 获得obj中对应的属性值
set(Object obj, Object value) 设置obj中对应属性值

Method类

Method代表类的方法。














方法 用途
invoke(Object obj, Object… args) 传递object对象及参数调用该对象对应的方法

Constructor类

Constructor代表类的构造方法。














方法 用途
newInstance(Object… initargs) 根据传递的参数创建类的对象

获取Class类对象的三种方法

在反射中,要获取一个类或调用一个类的方法,我们首先需要获取到该类的 Class 对象。

在 Java API 中,获取 Class 类对象的三种方法
方法一:使用 Class.forName 静态方法。当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。但可能抛出 ClassNotFoundException 异常
Class<?> classBook = Class.forName(“com.fanshe.Book”);

方法二:这种方法只适合在编译前就知道操作的 Class。直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高,这说明任何一个类都有一个隐含的静态成员变量 class
Class clz = Book.class;

方法三:使用类对象的 getClass() 方法。
Book book1 = new Book();
Class<? extends Book> book1Class = book1.getClass();

代码示例:

  1. @Test
  2. public void getClz() {
  3. try {
  4. // 方法一,使用 Class.forName 静态方法
  5. Class<?> classBook = Class.forName("com.fanshe.Book");
  6. // 方法二:直接通过 类名.class 的方式得到
  7. Class clz = Book.class;
  8. // 方法三:使用类对象的 getClass() 方法。
  9. Book book1 = new Book();
  10. Class<? extends Book> book1Class = book1.getClass();
  11. System.out.println(classBook == clz);
  12. System.out.println(classBook == book1Class);
  13. } catch (Exception ex) {
  14. ex.printStackTrace();
  15. }
  16. }
  17. 执行结果:
  18. true
  19. true

反射常用类和方法

  1. public class ReflectClass {
  2. // 创建类的实例
  3. @Test
  4. public void reflectNewInstance() {
  5. try {
  6. Class<?> classBook = Class.forName("com.fanshe.Book");
  7. Object objectBook = classBook.newInstance();
  8. Book book = (Book) objectBook;
  9. book.setName("Java高级特性-反射-创建对象");
  10. book.setAuthor("Yang");
  11. System.out.println(book.toString());
  12. } catch (Exception ex) {
  13. ex.printStackTrace();
  14. }
  15. }
  16. // 反射私有的构造方法
  17. @Test
  18. public void reflectPrivateConstructor() {
  19. try {
  20. Class<?> classBook = Class.forName("com.fanshe.Book");
  21. Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class, String.class);
  22. // 暴力反射
  23. declaredConstructorBook.setAccessible(true);
  24. Object objectBook = declaredConstructorBook.newInstance("Java高级特性-反射-反射私有的构造方法", "Yang");
  25. Book book = (Book) objectBook;
  26. System.out.println(book.toString());
  27. } catch (Exception ex) {
  28. ex.printStackTrace();
  29. }
  30. }
  31. // 反射私有属性
  32. @Test
  33. public void reflectPrivateField() {
  34. try {
  35. Class<?> classBook = Class.forName("com.fanshe.Book");
  36. Object objectBook = classBook.newInstance();
  37. Field fieldTag = classBook.getDeclaredField("TAG");
  38. fieldTag.setAccessible(true);
  39. String tag = (String) fieldTag.get(objectBook);
  40. System.out.println(tag);
  41. } catch (Exception ex) {
  42. ex.printStackTrace();
  43. }
  44. }
  45. // 反射私有方法
  46. @Test
  47. public void reflectPrivateMethod() {
  48. try {
  49. Class<?> classBook = Class.forName("com.fanshe.Book");
  50. Method methodBook = classBook.getDeclaredMethod("declaredMethod", int.class);
  51. methodBook.setAccessible(true);
  52. Object objectBook = classBook.newInstance();
  53. String string = (String) methodBook.invoke(objectBook, 0);
  54. System.out.println(string);
  55. } catch (Exception ex) {
  56. ex.printStackTrace();
  57. }
  58. }
  59. }
  60. 执行结果:
  61. Book{
  62. name='Java高级特性-反射-创建对象', author='Yang'}
  63. Book{
  64. name='Java高级特性-反射-反射私有的构造方法', author='Yang'}
  65. BookTag
  66. I am declaredMethod 0 !

通过反射获取私有属性,方法和构造方法时,需要进行暴力反射,设置setAccessible(true)。否则会报错说无法获取私有属性,方法和构造方法

总结

本文列举了反射机制使用过程中常用的、重要的一些类及其方法,更多信息和用法,反射原理和源码分析需要近一步的阅读反射相关资料。

在阅读Class类文档时发现一个特点,以通过反射获得Method对象为例,一般会提供四种方法,getMethod(parameterTypes)、getMethods()、getDeclaredMethod(parameterTypes)和getDeclaredMethods()。getMethod(parameterTypes)用来获取某个公有的方法的对象,getMethods()获得该类所有公有的方法,getDeclaredMethod(parameterTypes)获得该类某个方法,getDeclaredMethods()获得该类所有方法。带有Declared修饰的方法可以反射到私有的方法,没有Declared修饰的只能用来反射公有的方法。其他的Annotation、Field、Constructor也是如此。

发表评论

表情:
评论列表 (有 0 条评论,146人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java反射机制

    百科: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法

    相关 Java反射机制

    Java反射机制 > 定义:在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性(包括私有的方法和属性)进行调

    相关 java反射机制

    什么是反射 > 反射是一种计算机处理方式。有程序可以访问、检测和修改它本身状态或行为的这种能力。能提供封装程序集、类型的对象。(程序集包含模块,而模块包含类型