Java反射

反射

学习反射

反射就是:加载类、并允许以编程的方式解刨类中的各种成分(成员变量、方法、构造器)

  1. 反射第一步:加载类,获取类的字节码:class对象

    获取Class对象的三种方法

    • Class c1 = 类名.class

    • 调用Class提供方法:public static Class forName(String package);

    • Object调用的方法:public Class getClass(); Class c3 = 对象.getClass();

      定义一个Student类

      import lombok.Data;
      
      @Data
      public class Student {
          private String name;
          private int age;
      }
      

      反射的第一步:获取类本身

      public class RelectDemo1 {
          public static void main(String[] args) throws Exception {
              // 反射的第一步
      
              //1.获取类本身:类.class
              Class c1 = Student.class;
              System.out.println(c1);
      
              //2.获取类本身:Class.forName("类的全类名")
              Class c2 = Class.forName("demo2reflect.Student");
              System.out.println(c2);
      
              //3.获取类本身:对象.getClass()
              Student s = new Student();
              Class c3 = s.getClass();
              System.out.println(c3);
      
              System.out.println(c1 == c2);//true
              System.out.println(c2 == c3);//true
          }
      }
      
  2. 获取类的构造器:Constructor对象

    Class提供了从类中获取构造器的方法。

方法说明
Constructor<?>[] getConstructors()获取全部构造器(只拿取public修饰的)
Constructor<?>[] getDeclaredConstryctors()获取全部构造器(只要存在就能拿到)
Constructor getConstructor(Class<?>… parameterTypes)获取某个构造器(只能获取public修饰的)
Constructor getDeclaredConstructor(Class<?>… parameterTypes)获取某个构造器(只要存在就能拿到)

获取类构造器的作用:依然是初始化对象返回

Constructor提供的方法说明
T newInstance(Object…intargs)调用次构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)

定义Dog类对象用于测试


public class Dog {
    private String name;
    private int age;
    private String hobby;
    private Dog() {

    }
    private void eat(){
        System.out.println("狗吃骨头");
    }
    public String eat(String name){
        System.out.println("狗吃"+name);
        return "狗说:谢谢!谢谢!";
    }
    private Dog(String name) {
        this.name = name;
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

获取类的构造器并进行操作

	@Test
    public void getConstructorInfo() throws Exception {
        //获取类的构造器对象并对进行操作
        //1.反射的第一步:获取Class对象,代表拿到类
        Class c1 = Dog.class;
        //2.获取构造器对象
        Constructor[] cons = c1.getDeclaredConstructors();
        for (Constructor con : cons) {
            System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
        }
        //3.获取单个构造器
        Constructor con = c1.getDeclaredConstructor();
        System.out.println(con.getName() + "(" + con.getParameterCount() + ")");

        Constructor con2 = c1.getDeclaredConstructor(String.class, int.class);
        System.out.println(con2.getName() + "(" + con2.getParameterCount() + ")");

        //4.创建对象
        //暴力反射:暴力反射,可以访问私有的属性,方法,构造器
        con.setAccessible(true);//暴力反射
        Dog d1 = (Dog) con.newInstance();
        System.out.println(d1);//输出:Dog{name='null', age=0, hobby='null'}

        Dog d2 = (Dog) con2.newInstance("小黑", 2);
        System.out.println(d2);//输出:Dog{name='小黑', age=2, hobby='null'}
    }
  1. 获取类的成员变量:Field对象

    Class提供了从类中获取成员变量的方法。

    方法说明
    public Field[] getFields()获取类的全部成员变量(只能获取public修饰的)
    public Field[] getDeclaredFields()获取类的全部成员变量(只要存在就能拿到)
    public Field getField(String name)获取类的某个成员变量(只能获取public修饰的)
    public Field getDeclaredField(String name)获取类的某个成员变量(只要存在就能拿到)

    获取到成员变量的作用:依然是赋值,取值。

    方法说明
    void set(Object obj,Object value)赋值
    Object get(Object obj)取值
    public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)

    获取类的成员方法并进行操作

      	@Test
        public void getFieldInfo() throws Exception {
            //目标:获取类的成员变量信息
            //1.获取Class对象
            Class c1 = Dog.class;
            //2.获取成员变量对象
            Field[] fields = c1.getDeclaredFields();
            for (Field field : fields) {
                System.out.println(field.getName() + "(" + field.getType().getName() + ")");
            }
            //3.获取单个成员变量对象
            Field field = c1.getDeclaredField("hobby");
            System.out.println(field.getName() + "(" + field.getType().getName() + ")");
    
            Field field2 = c1.getDeclaredField("age");
            System.out.println(field2.getName() + "(" + field2.getType().getName() + ")");
            //4.获取成员变量的目的依然是取值和赋值
            Dog d = new Dog("泰迪", 2);
            field.setAccessible(true);
            field.set(d, "睡觉");
            System.out.println(d);//输出:Dog{name='泰迪', age=2, hobby='睡觉'}
    
            String hobby = (String) field.get(d);
            System.out.println(hobby);//输出:睡觉
        }
    
  2. 获取类的成员方法:Method对象

    Class提供了从类中获取成员方法的API

    方法说明
    Method[] getMethods()取类的全部成员方法(只能获取public修饰的)
    Method[] getDeclaredMethods()获取类的全部成员方法(只要存在就能拿到)
    Method getMethod(String name,Class<?>…parameterTypes)获取类的某个成员方法(只能获取public修饰的)
    Method getDeclaredMethod(String name,Class<?>…parameterTypes)获取类的某个成员方法(只要存在就能拿到)

    成员方法的作用:依然是执行

    Method提供的方法说明
    public Object invoke(Object obj,Object…args)触发某个对象的该方法执行
    public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)

    获取类的成员方法并进行操作

      	@Test
        public void getMethodInfo() throws Exception {
            //目标:获取类的成员方法信息
            //1.获取Class对象
            Class c1 = Dog.class;
            //2.获取成员方法对象
            Method[] methods = c1.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println(method.getName() + "(" + method.getParameterCount() + ")");
            }
            //3.获取单个成员方法对象
            Method m1 = c1.getDeclaredMethod("eat");//获取的是无参数的eat方法
            Method m2 = c1.getDeclaredMethod("eat", String.class);//获取的是有参数的eat方法
    
            System.out.println(m1.getName() + "(" + m1.getParameterCount() + ")");
            System.out.println(m2.getName() + "(" + m2.getParameterCount() + ")");
    
            Dog d = new Dog("泰迪", 4);
            m1.setAccessible(true);
            Object re1 = m1.invoke(d);//唤醒对象的eat方法,相当于d.eat();
            System.out.println(re1);//
    
            Object re2 = m2.invoke(d, "骨头");//唤醒对象的eat方法,相当于d.eat("骨头");
            System.out.println(re2);
        }
    

完整代码展示


import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectDemo2 {
    @Test
    public void getClassInfo() {
        // 获取类信息
        Class c1 = Student.class;
        System.out.println(c1.getName());//类的全类名 demo2reflect.Student
        System.out.println(c1.getSimpleName());//类名 Student
    }

    @Test
    public void getConstructorInfo() throws Exception {
        //获取类的构造器对象并对进行操作
        //1.反射的第一步:获取Class对象,代表拿到类
        Class c1 = Dog.class;
        //2.获取构造器对象
        Constructor[] cons = c1.getDeclaredConstructors();
        for (Constructor con : cons) {
            System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
        }
        //3.获取单个构造器
        Constructor con = c1.getDeclaredConstructor();
        System.out.println(con.getName() + "(" + con.getParameterCount() + ")");

        Constructor con2 = c1.getDeclaredConstructor(String.class, int.class);
        System.out.println(con2.getName() + "(" + con2.getParameterCount() + ")");

        //4.创建对象
        //暴力反射:暴力反射,可以访问私有的属性,方法,构造器
        con.setAccessible(true);//暴力反射
        Dog d1 = (Dog) con.newInstance();
        System.out.println(d1);//输出:Dog{name='null', age=0, hobby='null'}

        Dog d2 = (Dog) con2.newInstance("小黑", 2);
        System.out.println(d2);//输出:Dog{name='小黑', age=2, hobby='null'}
    }

    @Test
    public void getFieldInfo() throws Exception {
        //目标:获取类的成员变量信息
        //1.获取Class对象
        Class c1 = Dog.class;
        //2.获取成员变量对象
        Field[] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName() + "(" + field.getType().getName() + ")");
        }
        //3.获取单个成员变量对象
        Field field = c1.getDeclaredField("hobby");
        System.out.println(field.getName() + "(" + field.getType().getName() + ")");

        Field field2 = c1.getDeclaredField("age");
        System.out.println(field2.getName() + "(" + field2.getType().getName() + ")");
        //4.获取成员变量的目的依然是取值和赋值
        Dog d = new Dog("泰迪", 2);
        field.setAccessible(true);
        field.set(d, "睡觉");
        System.out.println(d);//输出:Dog{name='泰迪', age=2, hobby='睡觉'}

        String hobby = (String) field.get(d);
        System.out.println(hobby);//输出:睡觉
    }

    @Test
    public void getMethodInfo() throws Exception {
        //目标:获取类的成员方法信息
        //1.获取Class对象
        Class c1 = Dog.class;
        //2.获取成员方法对象
        Method[] methods = c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "(" + method.getParameterCount() + ")");
        }
        //3.获取单个成员方法对象
        Method m1 = c1.getDeclaredMethod("eat");//获取的是无参数的eat方法
        Method m2 = c1.getDeclaredMethod("eat", String.class);//获取的是有参数的eat方法

        System.out.println(m1.getName() + "(" + m1.getParameterCount() + ")");
        System.out.println(m2.getName() + "(" + m2.getParameterCount() + ")");

        Dog d = new Dog("泰迪", 4);
        m1.setAccessible(true);
        Object re1 = m1.invoke(d);//唤醒对象的eat方法,相当于d.eat();
        System.out.println(re1);//

        Object re2 = m2.invoke(d, "骨头");//唤醒对象的eat方法,相当于d.eat("骨头");
        System.out.println(re2);
    }
}

反射的作用和应用场景

  • 可以在运行时得到一个类的全部成分然后操作

  • 可以破坏封装性

  • 也可以破坏泛型的约束

  • 更重要的用途是适合:做Java高级框架

  • 基本上主流框架都会基于反射设计一些通用技术功能

反射案例

1.突破泛型的限制

搭建框架

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值