之前的文章,有小伙伴留言说希望出一篇反射的教程,那今天我们就来说一说反射。对,就是这么好,所有小伙伴在留言,私信中提的问题,我都会逐一解答,提的一些要求,我也会尽快安排时间写相关教程分享给大家,今天就来搞一波反射。
我们通过一个实际的例子来演示反射在编程中的应用,学一个技术,一定是要应用的,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水。相信通过这篇教程,会让你对反射有一个更深层次的认知。
首先简单介绍反射的概念:
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
如何理解反射?简单的一句话解释,将传统的开发思路反向逆转。
传统的方式是通过类创建对象:类 ---> 对象。
反射就是将这个过程逆转,通过对象得到类:对象 ---> 类。
通过对象得到的这个类该如何表示?
使用Class类来表示,此类是Java反射的源头,是用来描述其他类的类,Class类的每一个实例化对象就是对其他类的描述。
在Object类中定义了以下的方法,此方法将被所有子类继承:
public final Class getClass()。
也就是说每一个类,都可以调用getClass()方法获取对应的Class对象,用来描述目标类,我们将这个Class类叫做目标类的运行时类。
有了Class对象,能做什么?
调用Class对象的newInstance()方法,可以动态创建目标类的对象。
要求:
1)目标类必须有无参数构造方法。
2)外部方法有足够的权限访问目标类的构造方法。
除了动态创建目标类的对象,反射也可以动态调用对象的各种方法,访问成员变量。
Java反射机制提供的功能
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的成员变量和方法。
反射相关的主要API
java.lang.Class:描述一个类。
java.lang.reflect.Method:描述类的方法。
java.lang.reflect.Field:描述类的成员变量。
java.lang.reflect.Constructor:描述类的构造方法。
Class用来描述目标类的结构,叫做目标类的运行时类。
Class的常用方法:
public Class>[] getInterfaces()
返回运行时类实现的全部接口。
public Class Super T> getSuperclass()
返回运行时类的父类。
public Constructor[] getConstructors()
返回运行时类的public构造方法。
public Constructor[] getDeclaredConstructors()
返回运行时类的全部构造方法。
public Method[] getMethods()
返回运行时类的public方法。
public Method[] getDeclaredMethods()
返回运行时类的全部方法。
public Field[] getFields()
返回运行时类的public成员变量。
public Field[] getDeclaredFields()
返回运行时类的全部成员变量。
Method用来描述运行时类的方法。
Method的常用方法:
public Class> getReturnType()
返回方法的返回值类型。
public Class>[] getParameterTypes()
返回方法的参数列表。
public int getModifiers()
返回方法的访问权限修饰符。
public String getName();
返回方法名。
public Class>[] getExceptionTypes()
返回方法的异常信息。
Field用来描述运行时类的成员变量。
Field的常用方法:
public int getModifiers()
返回成员变量的访问权限修饰符。
public Class> getType()
返回成员变量的数据类型。
public String getName()
返回成员变量的名称。
Constructor用来描述运行时类的构造方法。
Constructor的常用方法:
public int getModifiers()
返回构造方法的访问权限修饰符。
public String getName()
返回构造方法名。
public Class>[] getParameterTypes()
返回构造方法参数列表。
反射在实际中的应用主要是动态创建对象,动态调用对象的方法。
1.创建对象:
调用Class类的newInstance()方法创建对象。
2.调用指定方法:
(1)通过Class类的getMethod(String name,Class…parameterTypes)方法获取一个Method对象,并设置此方法操作时所需要的参数类型。
(2)调用Object invoke(Object obj, Object[] args)方法,并向方法中传递目标obj对象的参数信息。
代码:
需求:
创建一个查询数据库的工具类,自动将SQL语句查询出的结果集,封装成不同的对象返回,一个简化版的MyBatis工具。
思路:
工具类查询方法的参数列表:Connection对象,SQL语句,目标运行时类对象clazz,数据表的id值。
1.通过Connection对象,SQL语句,id值查询出对应的结果集。
2.利用反射机制调用clazz的无参构造方法创建目标对象。
3.获取clazz的Filed,即目标类的所有成员变量。
4.找到与成员变量名相同的结果集字段,并获取字段值。
5.通过成员变量名找到对应的setter方法。
6.利用反射机制调用setter方法完成赋值。
实现步骤:
1.导入mysql驱动,c3p0数据源相关jar包。
2.创建c3p0-config.xml。
<?xml version="1.0" encoding="UTF-8"?>rootrootcom.mysql.jdbc.Driverjdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-855510205
3.创建数据表student,user。
DROP TABLE IF EXISTS `student`;CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(11) DEFAULT NULL, `address` varchar(11) DEFAULT NULL, `tel` varchar(255) DEFAULT NULL, `score` double(11,1) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.创建实体类Student,User。
package com.southwind.entity;public class Student { private int id; private String name; private String address; private String tel; private double score; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } @Override public String toString() { return "Student [id=" + id +