Java深度理解——反射

Java深度理解——反射


image-20210227150535437

反射是Java独有的技术,是Java技术的显著特点

反射是指对于任何一个类,在运行时都可以直接得到这个类的全部成分(构造器对象,成员变量对象,方法对象等)

反射的核心思想和关键就是得到编译以后的class文件对象

获取class类对象

Class:字节码文件的类型

Constructor:构造器的类型

Field:成员变量的类型

Method:方法的类型

反射技术的第一步永远是先得到Class对象,有三种方式获取:

  1. 类名.class
  2. 通过类的对象.getClass()方法
  3. class.forName(“类的全限名”)
//类名.class
Class c1 = Student.class;

//对象.getClass()
Student s = new Student();
Class c2 = s.getClass();

//Class.forName("类的全限名")
Class c3 = Class.forName("stage03.reflectDemo.Student");

Class类下的方法:

  • String getSimpleName(); 获得类名字符串:类名
    
  • String getName(); 获得类全名:包名+类名
    
  • T newInstance(); 创建class对象关联类的对象,其实底层也是调用无参构造器,已被淘汰
    
    System.out.println(c1.getSimpleName());//获取简名
    System.out.println(c1.getName());//获取全限名
    Student s1 = (Student) c1.newInstance();//调用无参构造器得到对象,已经过时
    

获取Constructor构造器对象

通过class类型获取构造器:

  1. Constructor getConstructor(Class...parameterTypes)根据参数匹配获取某个构造器,只能拿到public修饰的构造器
  2. Constructor getDeclaredConstructor(Class...parameterTypes)根据参数匹配某个构造器,只要申明就可以定位,不必关心构造器权限修饰符
  3. Constructor[] getConstructors()获取所有的构造器,只能拿public修饰的构造器
  4. Constructor[] getDeclaredConstructors():获取所有的构造器,不用关心权限修饰符

Constructor的API:

  1. T newInstance(Object...initargs):创建对象,注入构造器需要的数据
  2. void setAccessible(true)修改访问权限,true代表暴力反射攻破权限,false表示保留不可访问权限(暴力反射),注意:是一次性打开
public void createObject() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取class类对象
        Class c = Student.class;
        //定位有参数构造器对象
        Constructor constructor = c.getDeclaredConstructor(String.class,int.class);
        //暴力打开私有构造器的访问权限
        constructor.setAccessible(true);
        //通过有参数构造器初始化对象并返回
        Object swk = (Student)constructor.newInstance("张三", 18);
        System.out.println(swk);
    }
/**************Student类*************************/
package stage03.reflectDemo;

import lombok.Data;

/**
 * @author YJL
 */

public class Student {
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public Student() {
      System.out.println("无参构造器执行");
   }

   private String name;

   @Override
   public String toString() {
      return "Student{" +
              "name='" + name + '\'' +
              ", age=" + age +
              '}';
   }

   private int age;

   private Student(String name, int age) {
      this.name = name;
      this.age = age;
      System.out.println("有参构造器执行");
   }
}

执行结果:

image-20210724111537446

获取成员变量Field

  1. Field getField(String name);根据成员变量名获取对应Field对象,只要申明了就可以得到
  2. Field getDeclaredField(String name);根据成员变量名获得对应Field对象,只要申明了就可以得到
  3. Field[] getFields();根据获得所有成员变量对应的Field对象,只能获得public的
  4. Field[] getDeclaredFields();根据获得所有成员变量对应的Field对象,只要申明了就可以得到

实例成员变量,静态成员变量,常量全部可以获取到

给成员变量取值和赋值

  1. void set(Object obj,Object Value);给对象注入某个成员变量数据(参数一:被赋值的对象,参数二:该成员变量的值)
  2. Object get(Object Obj);获取对象的成员变量的值;
  3. void setAccessible(true):暴力反射
  4. Class getTye:获取属性的类型,返回Class对象
  5. String getName():获取属性的名称。

eg:

@Test
public void setField() throws Exception {
    //获取Class对象
    Class<Student> c = Student.class;
    //获取成员变量
    Field name = c.getDeclaredField("name");
    //先创建对象
    Student student = new Student();
    //暴力反射
    name.setAccessible(true);
    //赋值
    name.set(student,"张三");
    System.out.println(student.getName());
}
/****************Studnet类**********************/
package stage03.reflectDemo;

import lombok.Data;

/**
 * @author YJL
 */

public class Student {
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public Student() {
      System.out.println("无参构造器执行");
   }

   private String name;

   @Override
   public String toString() {
      return "Student{" +
              "name='" + name + '\'' +
              ", age=" + age +
              '}';
   }

   private int age;

   private Student(String name, int age) {
      this.name = name;
      this.age = age;
      System.out.println("有参构造器执行");
   }
}

执行结果:

image-20210724143928398

获取Method方法对象

  1. Method getMethod(String name,Class...args)根据方法名和参数类型获得相应的方法对象,只能获得public的

  2. Method getDeclaredMethod(String name,Class...args)根据方法名和参数类型获得相应的方法对象,包括private

  3. Method getMethods():获得类中所有的成员方法,返回数组,只能获得public修饰的且包含父类的

  4. Method getDeclaredMethods():获得类中的所有成员方法对象,返回数组,获得苯类声明的所有方法

  5. invoke(Object obj,Object...args):执行方法

    参数一:触发的是那个对象的方法执行

    参数二:args:调用方法时传递的实际参数

@Test
public void getDeclaredMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    //获取class类对象
    Class<Student> c = Student.class;
    //获取方法
    Method study = c.getDeclaredMethod("study",String.class);
    //暴力反射
    study.setAccessible(true);
    //创建对象
    Student student = new Student();
    //执行
    study.invoke(student,"测试");
}
/*****************Student***************/
public class Student {
   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public Student() {
      System.out.println("无参构造器执行");
   }

   private String name;

   @Override
   public String toString() {
      return "Student{" +
              "name='" + name + '\'' +
              ", age=" + age +
              '}';
   }

   private int age;

   private Student(String name, int age) {
      this.name = name;
      this.age = age;
      System.out.println("有参构造器执行");
   }

   private void study(String s){
      System.out.println("方法执行");
   }

执行结果:

image-20210724202256792

反射的小应用:

暴力破解泛型的约束:

泛型只能在工作阶段编译,运行阶段就消失了,而反射工作在运行阶段

@Test
public void destroyGeneric() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    ArrayList<Integer> arrayList = new ArrayList<>();
    arrayList.add(1);
    arrayList.add(2);
    arrayList.add(3);
    Class<? extends ArrayList> aClass = arrayList.getClass();
    Method add = aClass.getDeclaredMethod("add", Object.class);
    add.invoke(arrayList,"测试");
    System.out.println(arrayList);

}

运行结果:

image-20210724205024352

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值