李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
Java反射技术简介
Leefs
2020-11-07 PM
2073℃
0条
# Java反射技术简介 ### 一、前言 ##### 1.1 Java程序运行流程 ![06.Java反射技术简介01-Java程序运行流程.png](https://lilinchao.com/usr/uploads/2020/11/3037118233.png) 相信大家在初学Java时都听过两个词:==编译时异常==和==运行时异常==。 **编译时异常:**在Java通过编译器由.Java文件编译成.class的字节码文件时出现的语法上的异常。 **运行时异常:**通过Java解释器加载进内存出现的如内存溢出、数组角标越界等异常。 **1.2 正射和反射** **正射:**发生在Java代码编译时期,代码在编译时期就已经知道需要操作哪些类,以及调用类中的哪些方法。如果调用方法错误会在编译时期直接报错。 代码示例: ```java Student student = new Student(); //直接初始化,「正射」 student.setName("张三"); ``` **反射:**运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。 **总结:**动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制 ### 二、反射的概念 #### **官方解析** Oracle 官方对反射的解释是: ```english 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. ``` Java的**反射机制**是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意的一个方法;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。 #### 三、获取Class对象的三种方式 **3.1使用`Class.forName`静态方法** ```java Class personClass = Class.forName("com.llc.blog.reflection.domain.Person"); ``` **3.2 使用`类.class`方法** ```java Class personClass2 = Person.class; ``` **3.3 使用实例对象的`getClass()`方法** ```java Person person = new Person(); Class personClass3 = person.getClass(); ``` **完整代码:** ```java public class relectionDemo { public static void main(String[] args) throws Exception { Class personClass = Class.forName("com.llc.blog.reflection.domain.Person"); System.out.println(personClass.getName()); Class personClass2 = Person.class; System.out.println(personClass2.getName()); Person person = new Person(); Class personClass3 = person.getClass(); System.out.println(personClass3.getName()); } } ``` **运行结果** ```java com.llc.blog.reflection.domain.Person com.llc.blog.reflection.domain.Person com.llc.blog.reflection.domain.Person ``` #### 四、反射API介绍 ##### 4.1 通过反射获取无参/有参构造方法 **获取“公有”构造方法:** > + Constructor[] getConstructors():获取所有的"公有"构造方法; > > + public Constructor getConstructor(Class ... parameterTypes):获取某个公有的构造方法 ```java public class relectionDemo { public static void main(String[] args) throws Exception { Class personClass = Class.forName("com.llc.blog.reflection.domain.Person"); //------------------------------获取公共构造方法---------------- Constructor[] constructors = personClass.getConstructors(); System.out.println("-------------遍历所有公共的构造方法---------"); for(Constructor c: constructors){ System.out.println(c); } System.out.println("--------------获取单个,公有,无参的构造方法,并调用---------------"); Constructor constructor = personClass.getConstructor();//获取无参构造方法 Object obj = constructor.newInstance(); System.out.println("obj="+obj); System.out.println("--------------获取单个,公有,带参的构造方法,并调用--------------"); constructor = personClass.getConstructor(String.class,String.class,String.class); Object obj2 = constructor.newInstance("张三", "27", "男"); System.out.println("obj2="+obj2); } } ``` **运行结果** ```java -------------遍历所有公共的构造方法--------- public com.llc.blog.reflection.domain.Person(java.lang.String,java.lang.String,java.lang.String) public com.llc.blog.reflection.domain.Person() --------------获取单个,公有,无参的构造方法,并调用--------------- obj=Person{name='null', age='null', sex='null'} --------------获取单个,公有,带参的构造方法,并调用-------------- obj2=Person{name='张三', age='27', sex='男'} ``` **获取“所有(包括私有)”构造方法:** > + Constructor[] getDeclaredConstructors()::获取所有的(包括私有的)构造方法; > > + public Constructor getDeclaredConstructor(Class>... parameterTypes):获取某个构造方法(包括私有的) ```java public class relectionDemo04 { public static void main(String[] args) throws Exception { Class personClass = Class.forName("com.llc.blog.reflection.domain.Person"); System.out.println("------------------------------获取所有的构造方法(包括私有)---------------"); Constructor[] constructors = personClass.getDeclaredConstructors(); for(Constructor c:constructors){ System.out.println(c); } System.out.println("------------------------------获取所有的构造方法(包括私有),并调用---------------"); Constructor declaredConstructor = personClass.getDeclaredConstructor(String.class); declaredConstructor.setAccessible(true);//如果是私有的设置暴力访问,不然会出现IllegalAccessException异常 Object instance = declaredConstructor.newInstance("张三"); System.out.println(instance); } } ``` **运行结果** ```java ------------------------------获取所有的构造方法(包括私有)--------------- public com.llc.blog.reflection.domain.Person(java.lang.String,java.lang.String,java.lang.String) private com.llc.blog.reflection.domain.Person(java.lang.String) public com.llc.blog.reflection.domain.Person() ------------------------------获取所有的构造方法(包括私有),并调用--------------- Person{name='张三', age='null', sex='null'} ``` 实体类 ```java public class Person { private String name; private String age; private String sex; public Person() { } private Person(String name) { this.name = name; } public Person(String name, String age, String sex) { this.name = name; this.age = age; this.sex = sex; } } ``` ##### 4.2 通过反射获取成员变量 **获取公有的成员变量** > + Field[] getFields():获取所有公有的成员变量 > > + Field getField():获取单个,公有的成员变量 ```java public class relectionDemo { public static void main(String[] args) throws Exception { Class studentClass = Class.forName("com.llc.blog.reflection.domain.Student"); System.out.println("----------------获取所有公有的成员变量-------------"); Field[] fieldArray = studentClass.getFields(); for(Field f : fieldArray){ System.out.println(f); } System.out.println("----------------获取所有公有的成员变量,并赋值-------------"); Field f = studentClass.getField("name"); //赋值前,一定要确保堆中有"对象空间",所有要先创建一个对象 Object obj = studentClass.getConstructor().newInstance();//调用公有无参的构造方法 f.set(obj,"李林超博客"); //验证 Student stu = (Student)obj; System.out.println("Student的 name = " + stu.name); } } ``` **运行结果** ```java ----------------获取所有公有的成员变量------------- public java.lang.String com.llc.blog.reflection.domain.Student.name ----------------获取所有公有的成员变量,并赋值------------- Student的 name = 李林超博客 ``` **获取所有(包括私有)的成员变量** > + Field[] getDeclaredFields():获取所有成员变量(包括私有) > > + Field getDeclaredField():获取单个的成员变量,包括私有的 ``` public class relectionDemo { public static void main(String[] args) throws Exception { Class studentClass = Class.forName("com.llc.blog.reflection.domain.Student"); System.out.println("----------------获取所有的成员变量(包括私有)-------------"); Field[] declaredFields = studentClass.getDeclaredFields(); for(Field d:declaredFields){ System.out.println(d); } System.out.println("----------------获取所有的成员变量(包括私有),并赋值-------------"); Field address = studentClass.getDeclaredField("address"); Object obj = studentClass.getConstructor().newInstance();//调用公有无参的构造方法 address.setAccessible(true);//设置暴力访问 address.set(obj,"北京市"); //验证 Student stu = (Student)obj; System.out.println("address = " + stu.getAddress()); } } ``` **运行结果** ```java ----------------获取所有的成员变量(包括私有)------------- public java.lang.String com.llc.blog.reflection.domain.Student.name protected int com.llc.blog.reflection.domain.Student.age char com.llc.blog.reflection.domain.Student.sex private java.lang.String com.llc.blog.reflection.domain.Student.address ----------------获取所有的成员变量(包括私有),并赋值------------- address = 北京市 ``` **为成员变量赋值:** > + Filed --> set(Object obj,Object value) **实体类** ```java public class Student { public String name; protected int age; char sex; private String address; public String getAddress(){ return this.address; } } ``` **4.3 通过反射调用成员方法** **获取公有的成员方法** > + Method[] getMethods():获取所有公有的成员方法; > > + Method getMethod():获取单个公有的成员方法; ```java public class relectionDemo { public static void main(String[] args) throws Exception { Class studentClass = Class.forName("com.llc.blog.reflection.domain.Student"); System.out.println("*****************************获取所有公有的成员方法*****************************"); Method[] methodArray = studentClass.getMethods();//包含父类公有 for(Method m:methodArray){ System.out.println(m); } System.out.println("*****************************获取单个公有的,无参的并调用*****************************"); Method m = studentClass.getMethod("show1"); //实例化一个对象 Object obj = studentClass.newInstance(); m.invoke(obj); System.out.println("*****************************获取单个公有的,带参的,带返回值并调用*****************************"); Method method = studentClass.getMethod("show2", String.class, int.class); Object result = method.invoke(obj, "张三", 20);//传递参数,并接受返回值 System.out.println("返回值为:"+result); } } ``` **运行结果** ```java *****************************获取所有公有的成员方法***************************** public int com.llc.blog.reflection.domain.Student.show2(java.lang.String,int) public void com.llc.blog.reflection.domain.Student.show1() public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() *****************************获取单个公有的,无参的并调用***************************** 公有的,无参的show1()方法...... *****************************获取单个公有的,带参的,带返回值并调用***************************** 公有 show2()方法:s = 张三 , n = 20 返回值为:1000 ``` **获取所有的成员方法包括私有** > + Method[] getDeclaredMethods():获取所有的成员方法包括私有的。 > > + Method getDeclaredMethod():获取单个成员方法,包括私有的; ```java public class relectionDemo { public static void main(String[] args) throws Exception { Class studentClass = Class.forName("com.llc.blog.reflection.domain.Student"); /* System.out.println("*****************************获取所有公有的成员方法*****************************"); Method[] methodArray = studentClass.getMethods();//包含父类公有 for(Method m:methodArray){ System.out.println(m); } System.out.println("*****************************获取单个公有的,无参的并调用*****************************"); Method m = studentClass.getMethod("show1"); //实例化一个对象 Object obj = studentClass.newInstance(); m.invoke(obj); System.out.println("*****************************获取单个公有的,带参的,带返回值并调用*****************************"); Method method = studentClass.getMethod("show2", String.class, int.class); Object result = method.invoke(obj, "张三", 20);//传递参数,并接受返回值 System.out.println("返回值为:"+result);*/ System.out.println("*****************************获取所有的成员方法(包括私有的)*****************************"); Method[] declaredMethods = studentClass.getDeclaredMethods();//不包含继承的; for(Method d:declaredMethods){ System.out.println(d); } System.out.println("*****************************获取单个私有的,带参的并调用*****************************"); Method method = studentClass.getDeclaredMethod("show5", int.class); Object obj = studentClass.newInstance(); method.setAccessible(true);//暴力访问 method.invoke(obj,20); } } ``` **运行结果** ```java *****************************获取所有的成员方法(包括私有的)***************************** public int com.llc.blog.reflection.domain.Student.show2(java.lang.String,int) public void com.llc.blog.reflection.domain.Student.show1() private void com.llc.blog.reflection.domain.Student.show5(int) protected void com.llc.blog.reflection.domain.Student.show3(int) void com.llc.blog.reflection.domain.Student.show4(int) *****************************获取单个私有的,带参的并调用***************************** 私有的show5()方法:n = 20 ``` **调用方法:** > + Method --> public Object invoke(Object obj,Object... args) **实体类** ```java public class Student { public void show1(){ System.out.println("公有的,无参的show1()方法......"); } public int show2(String s,int n){ System.out.println("公有 show2()方法:s = " + s + " , n = " + n ); return 1000; } protected void show3(int n){ System.out.println("受保护的show3()方法:n = " + n); } void show4(int n){ System.out.println("默认的show4()方法:n = " + n); } private void show5(int n){ System.out.println("私有的show5()方法:n = " + n); } } ``` ### 五、获取Class对象对应的三个阶段 ![06.Java反射技术简介02--Java代码的三个阶段.bmp](https://lilinchao.com/usr/uploads/2020/11/143189088.bmp) > 1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象(Source源代码阶段) > * 多用于配置文件,将类名定义在配置文件中。读取文件,加载类 > 2. 类名.class:通过类名的属性class获取(Class类对象阶段) > * 多用于参数的传递 > 3. 对象.getClass():getClass()方法在Object类中定义着。(Runtime运行时阶段) > * 多用于对象的获取字节码的方式 附参考文章连接: *[参考文章1](https://www.cnblogs.com/linmusen/p/4709297.html),[参考文章2](https://blog.csdn.net/dylan95/article/details/102523929)*
标签:
Java
,
JavaSE
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/925.html
上一篇
【转载】Redis设置过期时间注意事项
下一篇
MySQL case when使用
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Http
Golang基础
JVM
高并发
二叉树
微服务
Livy
序列化和反序列化
Jquery
VUE
RSA加解密
pytorch
正则表达式
链表
Quartz
GET和POST
散列
Flink
JavaSE
Kafka
并发线程
CentOS
Yarn
字符串
JavaWEB项目搭建
持有对象
国产数据库改造
BurpSuite
线程池
Git
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭