反射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);
    }

posted on 2024-12-29 15:24  小木不痞  阅读(13)  评论(0)    收藏  举报

导航