反射引入?
(1)MyBatis如何做到给一个类型就可以把数据封装到这个类型的对象中去?
UserMapper文件中:
<select id="findUserById" parameterType="int" resultType="com.model.User">
<select id="findGradeById" parameterType="int" resultType="com.model.Grade">
(2)Servlet 中web.xml 配置:
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.servlet.LoginServlet</servlet-class>
</servlet>
(3)使用jdbc连接MySql数据库:
Class.forName("com.mysql.cj.jdbc.Driver");
注:框架的底层肯定是可以做到写一套代码,就可以对任何的类进行操作。
在这里,我们可以使用反射机制进行实现。
通过反射机制,来明白框架的底层原理是什么?
在之前,在java中是如何进行使用的一个类的?
class User{
}
User u = new User(); 对于我们的使用没有问题,因为我们知道项目中有哪些类。(因为我们自己进行创建类,然后使用类)
但是,我们在使用框架的时候,框架是事先不知道是哪个类的,在运行的时候(通过类的地址)才知道是哪个类,(框架不能直接进行创建对象 new 对象)
框架运行时,才会读取(解析)xml文件,才知道具体是哪个类,而且这个类可以是任意的。框架如何处理?
在运行时框架会创建该类的对象。
框架时如何做到的?
使用java中的反射机制。
什么是反射机制?
java反射机制,是在运行时,对于任意一个类(联想到框架可以处理任何类),都能够知道这个类中所有的信息(属性、方法、代码块等) 。可以创建此类的对象,并调用此类中的方法,这种动态获取类中信息,动态调用对象中的方法的功能,称为java的反射机制。
例:resultType="com.dao.Grade" : "com.dao.Grade" 只是一个字符串,但是这个字符串是类的地址,类中存放类的信息。
正向使用:
User u = new User(); 知道有这个类,才进行创建对象
反向使用:
反射其实就是一种反向对类的使用。(通过类的地址,动态获取类的信息,动态调用)
反射是如何具体实现的?
这种动态获取类的信息,动态创建对象,动态调用方式是如何具体实现的?
实现反射机制需要用到4各类
1. Class 类型
Class类的类,表示正在运行的Java应用程序中的类和接口
Class类是实现反射机制的根基。
一旦某个类被加载,就会在内存中创建一个Class类的对象,用来封装获取类的信息,一个类只有一个Class类的对象。
- Constructor 构造方法
- Method 方法
- Field 属性
注:除了Class外,其他类都位于java.lang.reflect中
创建Car类
public class Car {
private int no;
private int name;
private int price;
public Car() {
System.out.println("无参构造方法");
}
public Car(int no, int name, int price) {
this.no = no;
this.name = name;
this.price = price;
System.out.println("有参构造方法");
}
//getter和setter略
@Override
public String toString() {
return "Car{" +
"no=" + no +
", name=" + name +
", price=" + price +
'}';
}
}
Car car = new Car(); 以前使用类,是由虚拟机加载的,过程看不见
String classpash = "com.reflect.Car"
根据类的地址,将类的字节码加载到内存中,并为此类生成它的Class类的对象。
Class c = Class.forName(classpath);
Object car = c.newInstance();
创建传递过来的类的对象
通过Class类的对象,可以获得类的信息 例如获得类中的构造方法信息
获得指定的构造方法信息,将信息封装到Constructor对象中
无参构造方法:
Constructor cons1 = c.getConstructor();
有参构造方法:
Constructor cons2 = c.getConstructor(int.class,String.class,float.class);
通过Constructor类中的newInstance()创建对象
Object object1 = cons1.newInstance();
Object object2 = cons2.newInstance(1,"大众",100000);
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
String classpath = "com.reflect.Car";
//根据类的地址,将类的字节码加载到内存中,并为此类生成它的Class类的对象
Class c = Class.forName(classpath);
//通过Class类的对象,可以获得类的信息 例如获得类中的构造方法信息
Constructor cons1 = c.getConstructor();
Constructor cons2 = c.getConstructor(int.class,String.class,float.class);
//获得指定的构造方法信息,将信息封装到Constructor对象中
Object object1 = cons1.newInstance();
//通过Constructor类中的newInstance()创建对象
Object object2 = cons2.newInstance(1,"大众",100000);
}
}
一个Field类的对象表示类中一个属性
Field[] fields = c.getDeclaredFields(); 获得类中所有的属性for (Field f : fields){
String fname = f.getName(); 获得是属性名
根据属性名,生成set,get方法的名字,结合属性类型,获得对应属性的get/set方法
Method m = c.getMethod("set"+String.valueOf(fname.charAt(0)).toUpperCase() + fname.substring(1),f.getType());
System.out.println(m);
m.invoke(obj, 1); //动态调用获得到的set方法,为动态创建的对象属性赋值
}
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException,
IllegalAccessException, InstantiationException,
NoSuchMethodException, InvocationTargetException {
//resultType="com.ffyc.demo.model.User"
String classpath = "com.reflect.Car";
//根据类的地址,将类的字节码加载到内存中,并为此类生成它的Class类的对象
Class c = Class.forName(classpath);
Object obj = c.newInstance();
//一个Field类的对象表示类中一个属性
Field [] fields = c.getDeclaredFields();//获得类中所有的属性
for (Field f : fields){
String fname = f.getName();//获得是属性名
//根据属性名,生成set,get方法的名字,结合属性类型,获得对应属性的get/set方法
Method m = c.getMethod("set"+String.valueOf(fname.charAt(0)).toUpperCase()+fname.substring(1),f.getType());
System.out.println(m);
m.invoke(obj, 1); //动态调用获得到的set方法,为动态创建的对象属性赋值
}
System.out.println(obj);
}
}