当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。我们认为java并不是动态语言,但是java有一个非常突出的动态相关机制,俗称:反射。
IT行业里这么说,没有反射也就没有框架,现有的框架都是以反射为基础。在实际项目开发中,用的最多的是框架,填的最多的是类,反射这一概念就是将框架和类揉在一起的调和剂。
更多的可以回顾下C++ 结构体和类的区别,这里温习下
起初,“面向对象”是指在程序设计中采用封装、继承、多态等设计方法。现在,面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(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的实例对象。
在学习 Java 反射机制前,大家应该先分清楚两个概念: 编译期和运行期。
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 反射机制的时候所做的第一件事情
Java 反射机制在 web 开发框架, ORM 框架, 插件化开发等场景中得到了广泛运用。
比如说 web 开发框架 Spring 中,最重要的概念就是 IOC 控制反转。而 IOC 的实现原理就是反射。通过反射来构造 Java Bean 的对象,调用其方法。
比如说 Android 开发中常用的 ORM 框架: GreenDao, LiteOrm 等, 也是通过反射来读写 Java Bean 对象的成员变量的。
如果你只是使用这些框架,你可能感觉不到反射的存在,实际上反射却是无处不在。
在反射中,要获取一个类或调用一个类的方法,我们首先需要获取到该类的 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);
下面整理下:
与获取类属性一样,当我们去获取类方法、类构造器时,如果要获取私有方法或私有构造器,则必须使用有 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://www.zhoulujun.cn/html/java/KeyConcepts/8485.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。