Java之反射:Class类、调用构造方法、访问字段、访问方法

反射

什么是反射:

​ 反射是Java语法的一种高级特性,在“运行期间”对Java的类型信息进行检查,操作处理。例如:加载JDBC驱动类,Mybatis动态处理resultType,Spring根据配置创建Bean对象等使用场景都用反射实现

常见的反射操作:

  1. 获取Class类型信息
  2. 执行构造方法创建对象
  3. 调用实例方法
  4. 通过成员变量保存值和获取值

Class类

Class对象用于保存一个类的类型信息,它是反射的入口操作

获取Class对象的三种方式:

  1. 通过类名:

    Class cls = Book.class;
    
  2. 通过forName()方法:

    Class cls = Class.forName("com.dong.Book");
    
  3. 通过对象:

    Class cls = new Book().getClass();
    

类只加载一次,三个方法获取同一个类的Class对象,输出相同

Constructor类

代表一个类中的构造方法(构造器),用于创建“目标对象”

  • 获取Constructor构造方法的方式
  1. Class对象.getConstructor() 获取无参构造方法

    Class cls = Book.class;
    
    Constructor constructor1 = cls.getConstructor();  // 获取无参构造方法
    
  2. Class对象.getConstructor(Class…) 获取有参构造方法

    Class cls = Book.class;
    
    //	获取有参构造方法,在Book类中存在有参构造方法
    //	参数列表为:String,String,double,int
    Constructor constructor2 = cls.getConstructor(String.class,String.class,double.class,int.class);
    
  • 执行Constructor构造方法的方式
  1. Constructor对象.newInstance() 执行无参构造方法

    // 执行无参构造方法,创建目标对象
    Object obj = constructor1.newInstance();
    
  2. Constructor对象.newInstance(值…) 执行有参构造方法

    // 执行有参构造方法,创建目标对象
    Object obj = constructor2.newInstance("额尔古纳河右岸","迟子建",12.5,100);
    
  • 获取所有的构造方法

    Class<Book> cls = Book.class;
    Constructor[] constructors = cls.getConstructors();
    

总结:创建目标对象的方法(3种):

  1. 通过Class对象:

    Class<Book> cls = Book.class;
    Object obj = cls.newInstance();
    
  2. 通过无参构造方法

  3. 通过有参构造方法

Field类

代表一个类中的成员变量(字段),用于为“目标对象”保存值和获取值

  • 获取Field成员变量的方式
  1. 获取public修饰的成员变量:Class对象.getFields()

    Class cl = Book.getClass();
    Field[] fields = cl.getFields();
    
  2. 获取public/private修饰的成员变量:Class对象.getDeclaredFields()

    Class cl = Book.getClass();
    Field[] fields = cl.getDeclaredFields();
    
  • 使用Field成员变量的方式
  1. Class对象.getField(成员变量名称):public修饰的成员变量

    Class cl = Book.getClass();
    Field[] fields = cl.getFields("bookName");
    
  2. Class对象.getDeclaredField(成员变量名称):public\private修饰的成员变量

    Class cl = Book.getClass();
    Field[] fields = cl.getDeclaredFields("bookName");
    
  • 给Filed成员变量赋值:

    Field对象.set(目标对象,Value);

    // 获取需要创建的对象类型信息
    Class bookClass = Book.class;
    // 创建对象
    Object bookObj = bookClass.newInstance();
    // 获取该类型中bookName成员变量
    Field bookNameField = bookClass.getDeclaredField("bookName");
    
    // book对象.bookName = "舒克和贝塔"
    bookNameField.setAccessible(true);  
    // 由于Book类中bookName是私有的,所以需要设置
    bookNameField.set(bookObj, "舒克和贝塔");
    

    setAccessible:

    封装时,类的成员变量私有,将Field对象的accessible标志设置为ture表示:反射的对象在使用时应该取消 Java 语言访问检查;设置为false表示:反射的对象应该实施 Java 语言访问检查

  • 获取成员变量名称并获取变量值

    获取成员变量名称:Field对象.getName();

    获取变量值:Field对象.get(目标对象名);

    例:

    public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    	// 获取类型的信息对象
      Class<Book> cls = Book.class;
    
      // 创建目标对象
      Constructor constructor = cls.getConstructor(String.class,String.class,double.class,int.class);
      Object obj = constructor.newInstance("额尔古纳河右岸","迟子建",12.6,100);
      show(obj);
    }
    
    public static void show(Object obj) {
      try {
        Class cl = obj.getClass(); 
        Field[] fields = cl.getDeclaredFields();
        for(Field f  : fields) {
          f.setAccessible(true);
          System.out.println("属性"+f.getName());    // 获取成员变量属性
          System.out.println("属性值:"+f.get(obj));  // 获取变量属性值
        }
      } catch (SecurityException e) {
        e.printStackTrace();
      } catch (IllegalArgumentException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }
    

Method类

代表一个类中的方法,用于调用执行该方法

  • 获取Method方法的方式
  1. 获取指定名称和参数列表的Method:Class对象.getMethod(String name,Class…parameterTypes)

    在调用时,需要传入方法名,以及参数列表类型,eg:
    Class cls = Book.class;
    Method method = cls.getMethod("read",String.class,String.class);
    
  2. 获取所有的Method方法:Class对象.getMethods();

    Class cls = Book.class;
    Method[] methods = cls.getMethods();
    
    for(Method m : methods) {
      System.out.println(m);
      System.out.println("访问修饰符::"+m.getModifiers());   
      System.out.println("返回值类型:"+m.getReturnType());
      
      // 参数列表为一个Parameter类型的数组
      System.out.println("参数列表:");
      for(Parameter p : m.getParameters()) {
        System.out.println(p);
      }
      System.out.println("方法名称:"+m.getName());
      System.out.println();
    }
    
    • getModifiers():获取访问修饰符
    • getReturnType():获取返回值类型
    • getParameters():获取参数列表
    • getName():获取方法名称
  • 执行Method方法的方式

Method对象.invoke(目标对象,方法参数):

eg:读取配置文件调用方法

config.txt:

com.dong.Task
execute

Task类:

public class Task {
  public String execute(String id) {
    System.out.println("ִ执行流水号:" + id);
    System.out.println("ִ执行了Task任务类的excute方法!!!");
    return "ok";
  }
}

Job类:

public class Job {
	public String run(String id) {
		System.out.println("执行流水号:" + id);
		System.out.println("ִ执行了Job任务类的run方法!!!");
		return "success";
	}
}

Main方法:

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;

public class reflex07 {
  public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    // 读取配置文件调用方法,修改配置文件中内容执行不同的方法
    List<String> configList = Files.readAllLines(Paths.get("f:\\config.txt"));

    String className=configList.get(0);
    String methodName=configList.get(1);

    // 获取类信息
    Class<?> cl = Class.forName(className);

    // 获取方法
    Method method = cl.getMethod(methodName, String.class);

    // 执行方法
    Object obj = cl.newInstance();  // 创建目标对象
    Object returnVal = method.invoke(obj, UUID.randomUUID().toString());  		// 调用方法
 
    System.out.println("返回值:"+returnVal);
  }
}

通过Method对象.invoke(目标对象,参数列表)调用方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeMonkey-D

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值