反射

一、反射的基本概念

1、定义

  • Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类所有的属性和方法。
  • 对于任意一个对象,都能够调用它的任意一个方法和属性。
  • 这种动态获取信息和动态调用对象的功能被称作Java语言的反射机制。
  • 要想通过反射解剖一个类就必须先获得该类的字节码对象。
  • 解剖使用的就是Class类中的方法,所以要先获取每一个字节码文件对应的Class类型对象。
  • 通俗的讲,一个类的字节码文件对象就是这个类的骨架。

2、获取字节码对象的三种方式。

  • 对象.getClass();
  • 类名.Class;
  • Class类中的静态方法forName("类的全限定名");
    代码示例
public static void main(String[] args) throws Exception {
    Class<?> clazz =  Class.forName("com.qianfeng.Student");
    Student object = (Student)clazz.newInstance();
    object.method();
}

二、反射获取构造函数

1、定义

  • Class类中的newInstance()方法是使用该类的无参构造方法创建对象。
  • 如果一个类没有无参构造函数,那么就不呢个按照上述方法创建对象了,可以调用Class类中的getConstructor(String .class,int .class.....)方法获取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象。
  • 代码示例如下:
public static void main(String[] args) throws Exception {
    Class<?> clazz =  Class.forName("com.qianfeng.Student");
    Student object = (Student)clazz.newInstance();
    object.method();
    
}

2、榨汁机案例及分析

  • 分别有水果(Fruit)苹果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)
  • 根据客户的需求, 随时更换果汁
interface Fruit {
   public void squeeze();
}

class Apple implements Fruit {
   public void squeeze() {
       System.out.println("榨出一杯苹果汁儿");
   }
}

class Orange implements Fruit {
   public void squeeze() {
       System.out.println("榨出一杯桔子汁儿");
   }
}

class Juicer {
   public void run(Fruit f) {
       f.squeeze();
   }

}
public static void main(String[] args) throws Exception {
    
    //从本地读取配置文件
    BufferedReader br = new BufferedReader(new FileReader("config.txt"));
     //创建输入流对象,关联配置文件   
    Class<?> clazz = Class.forName(br.readLine());  //读取配置文件一行内容,获取该类的字节码对象
    Fruit f = (Fruit) clazz.newInstance();      //通过字节码对象创建实例对象
    Juicer j = new Juicer();
    j.run(f);
}

三、反射获取成员变量

1、定义

  • Class.getField(String str);方法可以获取类中指定的字段(可见的)。
  • 如果是私有的可以用Class.getDeclaedFiled(String )获取。
  • 然后通过调用setAccessible(true)设置访问权限放开。
  • 再通过get(Obj)和set(obj)可以获取和设定指定字段上该字段的值,Obj指的是这个类的对象。

2、代码示例

public static void main(String[] args) throws Exception {
    Student student = new Student();
    Class<?> clazz = Class.forName("com.qianfeng.Student");
    //获取共有的属性
    Field field = clazz.getField("name");
    //获取所有的属性
    Field field2 = clazz.getDeclaredField("name");
    //取消语言检查
    field2.setAccessible(true);
    //给一个对象的属性设置值
    field2.set(student, "333");
    //获取这个对象的属性的值
    String str= (String) field2.get(student);
    System.out.println(str);
    
}

四、反射获取成员方法

1、定义

  • Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法
  • 调用invoke(Object, Object...)可以调用对象的这个方法

2、代码示例

需求: 往一个ArrayList<Integer> 的对象中添加String类型的值。
泛型限定只会在编译过程中起作用,一旦程序开始运行泛型限定就失去了作用

package part02;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class Reflect02 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        ArrayList<Integer> list=new ArrayList<>();
        list.add(10);
        //通过对象获取.class文件
        Class<?> class1 = list.getClass();
        //获取“add()”方法。
        Method method = class1.getMethod("add", Object.class);
        //将add()方法暴力破解
        //method.setAccessible(true); 只有私有化的方法/属性才用破解
        //运行add();方法添加数据“小红”
        method.invoke(list, "小红");
        
        System.out.println(list);
        
        Method[] fields = class1.getDeclaredMethods();
        
        for(Method e:fields){
            e.setAccessible(true);
            System.out.println(e);
        }
    }
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。