• home > java > KeyConcepts >

    java反射机制原理剖析

    Author:zhoulujun Date:

    没有反射也就没有框架,现有的框架都是以反射为基础。 Spring 中,最重要的概念就是 IOC 控制反转。而 IOC 的实现原理就是反射。通过反射来构造 Java Bean 的对象,调用其方法。反射就是在运行时才知道要操作的类是什么,并且

    当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。我们认为java并不是动态语言,但是java有一个非常突出的动态相关机制,俗称:反射

    IT行业里这么说,没有反射也就没有框架,现有的框架都是以反射为基础。在实际项目开发中,用的最多的是框架,填的最多的是类,反射这一概念就是将框架和类揉在一起的调和剂。

    什么是类(Class)?

    更多的可以回顾下C++ 结构体和类的区别,这里温习下

    面向对象(Object Oriented,OO)

    起初,“面向对象”是指在程序设计中采用封装、继承、多态等设计方法。现在,面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(OOA,ObjectOriented Analysis),面向对象的设计(OOD,Object Oriented Design)、以及面向对象的编程实现(OOP,Object Oriented Programming)。

    对象和类解释:

    • 对象:对象是人们要进行研究的任何事物,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。对象具有状态,一个对象用数据值来描述它的状态。对象还有操作,用于改变对象的状态,对象及其操作就是对象的行为。对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中。

    • :具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象,类实际上就是一种数据类型。类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。

    对象和类的关系:

    类与对象的关系就如模具和铸件的关系,类的实例化化的结果就是对象,而对对象的抽象就是类,类描述了一组有相同特性(属性)和相同行为的对象。

    在java语言中,static修饰的东西不是对象,但是它属于类。普通的数据类型不是对象,例如:int a = 5;它不是面向对象,但是它有其包装类 Integer 或者分装类来弥补了它。除了以上两种不是面向对象,其余的包括类也有它的面向对象,类是java.lang.Class的实例化对象(注意Class是大写)。也就是说:

    Class A{}

    当我创建了A类,那么类A本身就是一个对象,谁的对象?java.lang.Class的实例对象。


    安利下《再谈编程范式—程序语言背后的思想》

    什么是反射(Reflection)

    在学习 Java 反射机制前,大家应该先分清楚两个概念: 编译期和运行期。

    编译期和运行期

    • 编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。

    • 运行期:是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。

    反射机制

    Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。概况就是:

    反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法

    Apple apple = new Apple(); //直接初始化,「正射」
    apple.setPrice(4);

    上面这样子进行类对象的初始化,我们可以理解为「正」。

    而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。

    这时候,我们使用 JDK 提供的反射 API 进行反射调用:

    Class clz = Class.forName("com.chenshuyi.reflect.Apple");
    Method method = clz.getMethod("setPrice", int.class);
    Constructor constructor = clz.getConstructor();
    Object object = constructor.newInstance();
    method.invoke(object, 4);

    上面两段代码的执行结果,其实是完全一样的。但是其思路完全不一样,第一段代码在未运行时就已经确定了要运行的类(Apple),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.chenshuyi.reflect.Apple)。

    在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息,而这个类在编译过程中甚至是还未存在的。在运行的时候我们可以通过配置文件获取某个类的类名,然后使用反射机制构造这个类的对象,调用这个对象的方法,修改这个对象的成员变量

    反射机制很重要的一点就是“运行时”,其使得我们可以在程序运行时加载、探索以及使用编译期间完全未知的 .class 文件。换句话说

    Java 程序可以加载一个运行时才得知名称的 .class 文件,然后获悉其完整构造,并生成其对象实体、或对其 fields(变量)设值、或调用其 methods(方法)一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。

    使用 Java 反射机制可以在运行时期检查 Java 类的信息,检查 Java 类的信息往往是你在使用 Java 反射机制的时候所做的第一件事情

    反射机制用处:

    1. 在运行时判断任意一个对象所属的类;

    2. 在运行时构造任意一个类的对象;

    3. 在运行时判断任意一个类所具有的成员变量和方法;

    4. 在运行时调用任意一个对象的方法;

    5. 生成动态代理。

    反射的使用场景

    Java 反射机制在 web 开发框架, ORM 框架, 插件化开发等场景中得到了广泛运用。

    比如说 web 开发框架 Spring 中,最重要的概念就是 IOC 控制反转。而 IOC 的实现原理就是反射。通过反射来构造 Java Bean 的对象,调用其方法

    比如说 Android 开发中常用的 ORM 框架: GreenDao, LiteOrm 等, 也是通过反射来读写 Java Bean 对象的成员变量的。

    如果你只是使用这些框架,你可能感觉不到反射的存在,实际上反射却是无处不在。

    反射常用API

    获取反射中的Class对象

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

    在 Java API 中,获取 Class 类对象有三种方法:

    第一种,使用 Class.forName 静态方法。当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。

        Class clz = Class.forName("java.lang.String");

    第二种,使用 .class 方法。这种方法只适合在编译前就知道操作的 Class。

        Class clz = String.class;

    第三种,使用类对象的 getClass() 方法。

        String str = new String("Hello");

        Class clz = str.getClass();

    通过反射创建类对象

    通过反射创建类对象主要有两种方式:通过 Class 对象的 newInstance() 方法、通过 Constructor 对象的 newInstance() 方法。

    第一种:通过 Class 对象的 newInstance() 方法。

    Class clz = Apple.class;
    Apple apple = (Apple)clz.newInstance();

    第二种:通过 Constructor 对象的 newInstance() 方法

    Class clz = Apple.class;
    Constructor constructor = clz.getConstructor();
    Apple apple = (Apple)constructor.newInstance();

    通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。

    Class clz = Apple.class;
    Constructor constructor = clz.getConstructor(String.class, int.class);
    Apple apple = (Apple)constructor.newInstance("红富士", 15);

    下面整理下:

    通过反射获取类属性、方法、构造器

    • getName() 方法返回类的全限定类名(包含包名)

    • getPackage() 获取包的相关信息,比如包名

    • getSuperclass() 访问类的父类

    • getInterfaces() 获取指定类所实现的接口集合(Class数组)

    • getConstructors() 获取 Constructor 类的实例

    • getMethods() 获取 Method 对象,Method 对象数组包含了指定类中声明为公有的(public)的所有变量集合

    • getModifiers() 访问一个类的修饰符, 即public,private,static 等等的关键字

    •  java.lang.reflect.Modifier 类中的方法来检查修饰符的类型

    • getFields() 访问一个类的成员变量,但无法获取私有属性

    • getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性

    与获取类属性一样,当我们去获取类方法、类构造器时,如果要获取私有方法或私有构造器,则必须使用有 declared 关键字的方法。


    反射源码解析

    们平常很多框架都使用了反射,而反射中最最终的就是 Method 类的 invoke 方法了

    具体查看 java.lang.reflect.Method.invoke 源码



    参考内容:

    Java-反射机制介绍 qiushao.net/2020/02/15/Java/Java-反射机制介绍/

    大白话说Java反射:入门、使用、原理 https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html

    Java Reflection(反射机制)详解 https://www.jianshu.com/p/2315dda64ad2

    谈谈Java反射机制 https://www.jianshu.com/p/6277c1f9f48d

    什么是类?什么是对象?类和对象有什么关系? https://blog.csdn.net/qq_34086047/article/details/51395730

    谈谈Java反射机制 https://www.jianshu.com/p/6277c1f9f48d

    JAVA反序列化 - 反射机制 https://xz.aliyun.com/t/7029



    转载本站文章《java反射机制原理剖析》,
    请注明出处:https://www.zhoulujun.cn/html/java/KeyConcepts/8485.html