反射的概念
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。(对于Java程序来说,状态和行为就是类的变量和方法)
反射是框架的灵魂!
反射的作用
* - 在运行时判断任意一个对象所属的类(对象.getClass().getName())
* - 在运行时构造任意一个类的对象(不用new,直接使用字节码文件对象就能给你创建对象)
User user1 =(User) class1.newInstance();
user1.say();
* - 在运行时判断任意一个类所具有的成员变量和方法
* - 在运行时调用任意一个对象的方法。通过反射甚至可以调用到private方法。
* - 生成动态代理(代理模式中的一种)
获得字节码文件的三种方式(没有字节码文件,反射就是空谈)
* - 对象.getClass() connection.getClass()
* - 使用Class类的forName()静态方法,全路径类名,该方法最常使用 Class.forName("com.mysql.jdbc.Driver");
* - 使用“类型名.class” 类似于User.class
* 这个方法其实不能单独使用,后面要加上函数,比如User.class.getName();
获取一个类的全路径名字的小技巧:
选中要获取的类,然后右键点击,选中:Copy Qualified Name
利用字节码生成对象
- 使用无参构造方法,只需调用这个类对应的Class对象的newInstance()方法
User user1 =(User) class1.newInstance();
使用带参数的构造函数生成对象
- Class对象调用getConstructor(参数类型的Class对象),获取带参数的构造函数;
- 构造函数调用newInstance(参数)生成对象
Class<?> forName = Class.forName("com.User");
Constructor<?> constructor = forName.getConstructor(int.class,String.class,String.class,String.class);
//获取到该类的有参数的构造函数
User user2 =(User) constructor.newInstance(2,"otra","123","rows");
//通过有参数的构造函数调用newInstance(参数)方法
user2.say();
Class对象的方法一览
- public String getName()
- 返回此 Class 对象所表示的实体的全限定名称。
-field.get(object)
可以获取指定对象object的某个变量的值。
如果要获取私有变量的值的话,要先把私有变量的权限设置了。
setAccessable(true); - public String getSimpleName()
- 返回此 Class 对象所表示的实体的全限定名称。 - public Field[] getFields()
- 返回此 Class 对象所表示的实体的所有公共属性。 - public Field[] getField(String name)
- 返回此 Class 对象所表示的实体的指定属性名称的公共属性。 - public Field[] getDeclaredFields()
- 返回此 Class 对象所表示的实体的所有属性,包括私有属性,但不包括继承父类的属性。 - public Method[] getMethods()
- 返回此 Class 对象所表示的实体的所有公共属性。(包括父类中的方法) - public Method[] getDeclaredMethods()
- 返回此 Class 对象表示的实体的所有方法,包括私有方法,但不包括继承父类的方法。 - public Method getMethod(String name, Class… parameterTypes)
- 返回此 Class 对象所表示的实体的指定公共成员方法,
- name指定方法名称,parameterTypes指定方法参数类型
- public Constructor[] getConstructors()
- 返回此 Class 对象所表示的类的所有公共构造方法。
- public Constructor[] getConstructors()
- public Constructor[] getDeclaredConstructors()
- 返回此 Class 对象表示的类声明的所有构造方法,包括私有构造方法。 - public Constructor getDeclaredConstructor(Class… parameterTypes)
- 返回此 Class 对象所表示的类的指定构造方法。 - public Class
- invoke(Object o,Object... args)
- o是调用该方法的对象,args是调用该方法时传入的参数
案例:
用反射自定义DBUtils,复写DBUtils框架的基本功能:
package com.itheima.myDBUtils;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
public class MyDBUtils{
DataSource ds;
public MyDBUtils(DataSource ds){
super();
this.ds = ds;
}
public <E> List<E> queryBeenList(String sql,Object[] params,Class<E> clazz) throws Exception{
//建立连接
Connection connection = ds.getConnection();
//创建执行sql语句的对象
PreparedStatement prepareStatement = connection.prepareStatement(sql);
//将参数导入都sql语句中去
if(params != null){
for(int i=0;i<params.length;i++){
prepareStatement.setObject(i+1, params[i]);
}
}
//执行sql语句
ResultSet resultSet = prepareStatement.executeQuery();
ResultSetMetaData metaData = prepareStatement.getMetaData();
//获得列数
int columnCount = metaData.getColumnCount();
Method[] methods = clazz.getMethods();
List<E> list = new ArrayList<>();
//处理结果集
while(resultSet.next()){
E e = clazz.newInstance();
//获取列名
for(int i=0;i<columnCount;i++){
//获取列名
String columnName = metaData.getColumnName(1+i);
//获取列的值
Object object = resultSet.getObject(columnName);
//设置值
for(int j=0;j<methods.length;j++){
if(methods[j].getName().equalsIgnoreCase("set"+columnName)){
methods[j].invoke(e, object);
}
}
}
list.add(e);
}
return list;
}
}
调用主函数类:
package com.itheima.myDBUtils;
import java.util.List;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class MainTest02 {
public static void main(String[] args) throws Exception {
MyDBUtils myDBUtils = new MyDBUtils(new ComboPooledDataSource());
String sql = "select * from userinfo";
List<User> user = myDBUtils.queryBeenList(sql, null, User.class);
System.out.println(user);
}
}