反射Reflect
概念
程序编译时不知道一个类的具体情况下,运行时获取该类的结构(构造方法,属性,方法),并执行该类相应的操作(调用构造,给属性赋值或者获取值,调用方法),这种机制就是反射。
准备
package com.aaa.reflect.entity;
/**
* @FileName: Emp
* @Description: 演示反射使用的实体
* @Author: zhz
* @CreateTime: 2024/11/19 8:46
* @Version: 1.0.0
*/
public class Emp {
//员工编号
private Integer empNo;
//员工姓名
private String empName;
//员工工作
private String job;
//员工薪资
private Double salary;
/**
* 自我介绍方法
*/
public void selfIntroduce(){
System.out.println("我的编号是:"+empNo+",我的名字叫:"+empName+",我的工作是:"+job);
}
/**
* 说话
* @param friendName
* @param typeName
* @return
*/
public String talk(String friendName,String typeName){
return "我是"+empName+",我正在和朋友"+friendName+"聊天,聊关于"+typeName+"的话题";
}
public Emp() {
}
public Emp(Integer empNo) {
this.empNo = empNo;
}
public Emp(Integer empNo, String empName) {
this.empNo = empNo;
this.empName = empName;
}
public Emp(Integer empNo, String empName, String job, Double salary) {
this.empNo = empNo;
this.empName = empName;
this.job = job;
this.salary = salary;
}
public Integer getEmpNo() {
return empNo;
}
public void setEmpNo(Integer empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
}
Class
概述
Class类是java语言反射的基础类。Class类的对象表示正在运行的Java应用程序中的类和接口。
类名.class
//1,通过类名.class获取
Class<Emp> empClass1 = Emp.class;
System.out.println(empClass1.getName());
对象.getClass()
//2,通过对象的getClass()获取
//实例化对象
Emp emp = new Emp();
Class<? extends Emp> empClass2 = emp.getClass();
System.out.println(empClass2.getName());
Class.forName()
//3,通过Class.forName(String classPath)获取
try {
Class<?> empClass3 = Class.forName("com.aaa.reflect.entity.Emp");
System.out.println(empClass3.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
ClassLoader对象.loadClass()
//4,通过ClassLoader获取
//获取类加载器
ClassLoader classLoader = GetClass.class.getClassLoader();
try {
//通过loadClass方法获取class对象
Class<?> empClass4 = classLoader.loadClass("com.aaa.reflect.entity.Emp");
System.out.println(empClass4.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
常用方法
其他
getName():返回由 类对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String 。
static forName('限定名'):返回与给定字符串名称的类或接口相关联的 类对象。
newInstance():创建由此 类对象表示的类的新实例
和属性相关的
getFields() :返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。
getField(String name):返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。
getDeclaredFields() :返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。
getDeclaredField(String name) :返回一个 Field对象,它反映此表示的类或接口的指定已声明字段 类对象。
和方法相关的
getDeclaredMethods() :返回包含一个数组 方法对象反射的类或接口的所有声明的方法,通过此表示 类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
getDeclaredMethod(String name, 类... parameterTypes):返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象。
**和构造相关的**
getDeclaredConstructors() :返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组 类 。
getDeclaredConstructor(类... parameterTypes) :返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数。
反射常用类
1.Constructor
概念
Constructor提供了一个类的单个构造函数的信息和访问。
常用方法
newInstance(Object... initargs):使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
实战
package com.aaa.reflect.demo;
import com.aaa.reflect.entity.Emp;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @FileName: ConstructorDemo
* @Description:
* @Author: zhz
* @CreateTime: 2024/11/19 9:39
* @Version: 1.0.0
*/
public class ConstructorDemo {
public static void main(String[] args) {
//1.获取Class对象
Class<Emp> empClass = Emp.class;
//使用常用方法,获取所有构造
Constructor<?>[] empDeclaredConstructors = empClass.getDeclaredConstructors();
//遍历
for (Constructor<?> constructor : empDeclaredConstructors) {
System.out.println(constructor);
}
System.out.println("==========================================");
//2.获取指定构造
try {
//Constructor<Emp> declaredConstructor = empClass.getDeclaredConstructor(Integer.class);
Constructor<Emp> declaredConstructor = empClass.getDeclaredConstructor(Integer.class,String.class);
System.out.println(declaredConstructor);
//使用Constructor类中的成员方法,实例化对象
//Emp emp = declaredConstructor.newInstance(1001);
Emp emp = declaredConstructor.newInstance(1001,"马云");
System.out.println(emp);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Field
概念
Field提供有关类或接口的单个字段的信息和动态访问
常用方法
set(Object obj, Object value):将指定对象参数上的此 Field对象表示的字段设置为指定的新值
get(Object obj) :返回该所表示的字段的值 Field ,指定的对象上。
setAccessible(boolean flag) :将此对象的 accessible标志设置为指示的布尔值。允许私有属性可访问。
实战
package com.aaa.reflect.demo;
import com.aaa.reflect.entity.Emp;
import java.lang.reflect.Field;
/**
* @FileName: FeildDemo
* @Description:
* @Author: zhz
* @CreateTime: 2024/11/19 10:31
* @Version: 1.0.0
*/
public class FieldDemo {
private static Field empNameField;
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
//获取class对象
Class<Emp> empClass = Emp.class;
//实例化空对象
Emp emp = empClass.newInstance();
//获取所有属性
//Field[] declaredFields = empClass.getFields(); //获取公共的,自己修改个属性
Field[] declaredFields = empClass.getDeclaredFields();
//遍历
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("=============================");
//获取指定属性
Field empNameField = empClass.getDeclaredField("empName");
System.out.println(empNameField);
//開啟反射,可以修改私有屬性,允許私有屬性賦值
empNameField.setAccessible(true);
//給屬性賦值
empNameField.set(emp,"马化腾");
System.out.println(emp);
//獲取值
Object empName = empNameField.get(emp);
System.out.println(empName);
}
}
Method
概念
方法提供有关类和接口上单一方法的信息和访问权限。
常用方法
invoke(Object obj, Object... args) :在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。
实战
package com.aaa.reflect.demo;
import com.aaa.reflect.entity.Emp;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @FileName: MethodDemo
* @Description:
* @Author: zhz
* @CreateTime: 2024/11/19 10:49
* @Version: 1.0.0
*/
public class MethodDemo {
public static void main(String[] args) throws Exception{
//获取class对象
Class<Emp> empClass = Emp.class;
//Emp emp = empClass.newInstance();
//获取所有方法
Method[] declaredMethods = empClass.getDeclaredMethods();
//遍历
for (Method method : declaredMethods) {
System.out.println(method);
int parameterCount = method.getParameterCount();
if(parameterCount!=0){
System.out.println("该方法的参数有"+parameterCount+"个,分别为:");
//获取所有参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
//遍历
for (Class<?> parameterType : parameterTypes) {
System.out.println("----------------"+parameterType);
}
}else {
System.out.println("该方法没有参数");
}
}
System.out.println("=====================================================");
//通过构造赋值
//Integer empNo, String empName, String job, Double salary
Constructor<Emp> declaredConstructor = empClass.getDeclaredConstructor(Integer.class, String.class, String.class, Double.class);
Emp emp1 = declaredConstructor.newInstance(1001, "马云", "CEO", 100000.00);
//获取指定方法
try {
//调用没有返回值的
//Method selfIntroduceMethod = empClass.getDeclaredMethod("selfIntroduce");
//调用带参有返回值的 //String friendName,String typeName
Method talkMethod = empClass.getDeclaredMethod("talk",String.class,String.class);
System.out.println(talkMethod);
//调用方法
Object returnValue = talkMethod.invoke(emp1,"马化腾","游戏");
System.out.println(returnValue);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
范例实战
需求
前面学习过jdbc封装工具类,用来链接数据库,查询或者更新数据,现在使用这节课学习的反射,封装一个查询方法,自动把任意一个表,映射为任意实体。(遵循一定的规则)
准备工作
在pom.xml文件引入jar
<dependencies>
<!--masql驱动包-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.32</version>
</dependency>
</dependencies>
拿到以前写的JDBC链接工具类,放入项目中,稍后进行改写
核心代码
/***
* 封装通用查询方法(传入的T的class对象,返回的是List<T> T泛指任意类)
* @param sql 执行的sql语句
* @param clazz T的class对象
* @param params 参数
* @return 返回的是List<T>
* @param <T>
*/
public static <T> List<T> executeQuery(String sql,Class<T> clazz,Object ...params){
//定义返回值
List<T> tList = new ArrayList<>();
//获取Connection
Connection connection = getMyConnection();
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//获取语句执行对象
try {
preparedStatement = connection.prepareStatement(sql);
//设置参数
setParams(preparedStatement, params);
//执行查询
resultSet = preparedStatement.executeQuery();
//获取元数据
ResultSetMetaData metaData = preparedStatement.getMetaData();
//根据元数据对象获取查询的sql列的数量
// select user_id,dept_id,real_name,user_name from sys_user columnCount=4
// select user_id,dept_id from sys_user columnCount=2
// ...
int columnCount = metaData.getColumnCount();
/**
*
* 1 1 管理员 admin t1
* 2 2 张代理 zhangzong t2
* 3 3 王商户 wangzong
* 13 1 张三 zhangsan
* 14 2 李四 lisi
* 15 3 王五 wangwu
* 16 1 李一四 liyisi
* 17 0 欧工 ougong
*/
//sql = select user_id,dept_id,real_name,user_name,.... from sys_user
//使用反射实例化一个对象
T t = null;
//循环结果
while (resultSet.next()){
//每循环一行,都实例化一个新对象 User t =null;
t = clazz.newInstance();
//每次都会获取一行数据
//再次循环获取每一行中的每一列数据
for ( int i = 1; i <= columnCount; i++){
//获取查询的列名称 select user_id,dept_id,real_name,user_name,user_name_aaa_bbb from sys_user
//第1次获取的是user_id
//第2次获取的是dept_id
//....
String columnName = metaData.getColumnName(i);
//获取列对应的属性名 columnName= user_id fieldName=userId
String fieldName = stringFirstLetterToUpperCase(columnName);
Field declaredField = clazz.getDeclaredField(fieldName);
//设置私有属性的访问权限
declaredField.setAccessible(true);
//赋值
declaredField.set(t,resultSet.getObject(i));
}
tList.add(t);
}
return tList;
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} finally {
closeAll(connection,preparedStatement,resultSet);
}
}
/**
* 字符串转换
* @param columnName user_name_aaa_bbb
* @return userNameAaaBbb
*/
public static String stringFirstLetterToUpperCase(String columnName) {
//判断columnName是否含有_
//没有直接返回
if(!columnName.contains("_")){
return columnName;
}
//存在就转换 user_name_aaa_bbb=["user","name","aaa","bbb"]
String[] columnNameArray = columnName.split("_");
//拼接字符串 stringBuilder="user"
StringBuilder stringBuilder =new StringBuilder(columnNameArray[0]);
for (int i = 1; i < columnNameArray.length; i++) {
//第1次 columnNameArray[1]=name
//第2次 columnNameArray[2]=aaa
//第3次 columnNameArray[2]=bbb
//...
String newString = columnNameArray[i].substring(0,1).toUpperCase()+columnNameArray[i].substring(1);
stringBuilder.append(newString);
}
return stringBuilder.toString();
}
public static void main(String[] args) {
String stringFirstLetterToUpperCase = stringFirstLetterToUpperCase("user_name_aaa_bbb");
System.out.println(stringFirstLetterToUpperCase);
}
浙公网安备 33010602011771号