反射的用法

反射机制的概念

由于对反射理解只停留在概念性的阶段,所以这篇文章只能简单的介绍下原理以及它的用法,java文件编译后变成class文件,也就是说java虚拟机实际上是运行的是class文件,在class文件中将java类中的各部分用它自己的方式进行表示,如一个java类中有方法,构造函数,变量,还有注解等等,这些东西,在java类中有Method,Filed,Constructor这三个类,在class文件中,有三个这样的数组分别是Method,Filed,Constructor的实例,我们用method,filed,constructor这三个变量表示,在method中包含了所有的方法,filed中包含了所有的变量,constructor中包含了所有的构造器函数,可以根据所有的 你传入的参数,方法名,变量名来进行判断你需要的是哪一个,并且动态的进行调用,获取(这些只是我本人看法,没经过验证,因为我还没有看过具体的class文件数据展示,而且这种机制我看别人的帖子总是很概念性的介绍,可能是我的知识量不够,觉得很空洞,苍白,所以以后再研究)

反射的用法

先定义一个类



import java.util.Date;

public class Person {
    public String name="李四";
    private int age = 18;
    public static int sex=1;
    public static Date date;
    public Person(){
        System.out.println("无参的构造函数");
    }

    private Person(int age){
        System.out.println(age);
    }
    //构造函数可以有多个,但是参数的类型和个数,以及顺序必须不一样,
    // 不然就会被默认为一样,如在下面的
   protected Person(int age,String name,Date date){
       System.out.println("获取保护类型的构造方法");
       System.out.println(age);
       System.out.println(name);
       System.out.println(date);
    }
    public Person(String name)
    {
        System.out.println(name);
    }
    //参数个数相同
    public Person(String name,int age)
    {
        System.out.println(name);
        System.out.println(age);
    }

    public Person(int age,String name)
    {

        System.out.println(age);
        System.out.println(name);
    }




    public void method1()
    {
        System.out.println("方法一");
    }

    public void method2(String name)
    {
        System.out.println("方法二"+name);
    }

    public void method3(int age)
    {
        System.out.println("方法三"+age);
    }
    public int method4(int age)
    {
        System.out.println("我是方法四");
        return age;
    }
    public String method5(String name)
    {
        System.out.println("我是方法五");
        return name;
    }
    private String method6(String sex)
    {
        System.out.println("我是方法6");
        return sex;
    }
    private static void method7()
    {
        System.out.println("我是方法7");
    }
    protected static void method8()
    {
        System.out.println("我是方法7");
    }




}

反射获取类的构造函数

/**
 * 获取构造方法,通过反射获取构造函数,主要是通过类所在的包名,获取到类的字节码对象(包名.类名)
 * 然后通过此类的字节码对象,调用获取构造函数的方法,并在方法里传入参数的字节码对象,在这里主要是通过
 * 参数的个数,类型,和顺序,进行判断,筛选(一个类中可能有多个构造函数),具体判断顺序我没有测试过,但是,我个人感觉先判断参数
 * 的个数,个数相同,看参数类型,类型可能有这样的一种情况,如(String,int)和(int,String),这就是两个不同的构造函数
 * Class类中与Constructor相关的方法
 1. Constructor getConstructor(Class... parameterTypes)
 * 根据参数类型获得对应的Constructor对象。
 * 只能获得public修饰的构造方法
 2. Constructor getDeclaredConstructor(Class... parameterTypes)
 * 根据参数类型获得对应的Constructor对象
 * 可以是public、protected、(默认)、private修饰符的构造方法。
 3. Constructor[] getConstructors()
 获得类中的所有构造方法对象,只能获得public的
 4. Constructor[] getDeclaredConstructors()
 获得类中的所有构造方法对象
 可以是public、protected、(默认)、private修饰符的构造方法。
 */
package test_2021_1_5.反射;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.util.Date;

/**
 * 获取构造方法,通过反射获取构造函数,主要是通过类所在的包名,获取到类的字节码对象(包名.类名)
 * 然后通过此类的字节码对象,调用获取构造函数的方法,并在方法里传入参数的字节码对象,在这里主要是通过
 * 参数的个数,类型,和顺序,进行判断,筛选(一个类中可能有多个构造函数),具体判断顺序我没有测试过,但是,我个人感觉先判断参数
 * 的个数,个数相同,看参数类型,类型可能有这样的一种情况,如(String,int)和(int,String),这就是两个不同的构造函数
 * Class类中与Constructor相关的方法
 1. Constructor getConstructor(Class... parameterTypes)
 * 根据参数类型获得对应的Constructor对象。
 * 只能获得public修饰的构造方法
 2. Constructor getDeclaredConstructor(Class... parameterTypes)
 * 根据参数类型获得对应的Constructor对象
 * 可以是public、protected、(默认)、private修饰符的构造方法。
 3. Constructor[] getConstructors()
 获得类中的所有构造方法对象,只能获得public的
 4. Constructor[] getDeclaredConstructors()
 获得类中的所有构造方法对象
 可以是public、protected、(默认)、private修饰符的构造方法。
 */
public class demo01 {
    @Test
    //获取一个参数类型为String的构造函数
    public void test01() throws Exception {
        //1.获取字节码对象的第一种方式
        Class aClass = Class.forName("test_2021_1_5.反射.Person");
        //传入参数的字节码对象
        Constructor constructor = aClass.getConstructor(String.class);
        constructor.newInstance("张三");


    }
    @Test
    //获取无参 的构造函数
    public void test02() throws Exception{
        Class aClass = Class.forName("test_2021_1_5.反射.Person");
        //无参,所以参数类型为null
        Constructor constructor = aClass.getConstructor(null);
        //无参,传入null
        constructor.newInstance(null);
    }
    @Test
    //获取两个参数的构造函数,String,int
    public void test03() throws  Exception{
        Class aClass = Class.forName("test_2021_1_5.反射.Person");
        Constructor constructor = aClass.getConstructor(String.class, int.class);
        constructor.newInstance("张三",15);
    }
    @Test
    //获取两个参数的构造函数,int,String
    public void test04() throws  Exception{
        Class aClass = Class.forName("test_2021_1_5.反射.Person");
        Constructor constructor = aClass.getConstructor(int.class,String.class);
        constructor.newInstance(15,"张三");
    }
    @Test
    //获取私有的构造方法
    public  void test05() throws Exception{
        Class aClass = Class.forName("test_2021_1_5.反射.Person");
// 注意:在反射私有的构造函数时,用普通的clazz.getConstructor()会报错,
// 因为它是私有的,所以提供了专门反射私有构造函数的方法 clazz.getDeclaredConstructor(int.class);
// 读取私有的构造函数,用这个方法读取完还需要设置一下暴力反射才可以

        Constructor constructor = aClass.getDeclaredConstructor(int.class);
        //获取私有的构造函数,必须进行暴力反射 ,设置"暴力反射"——是否取消权限检查,true取消权限检查,false表示不取消
        constructor.setAccessible(true);
        constructor.newInstance(20);
    }

    @Test
    //获取protected类型的构造函数,需要暴力反射
    public void test06() throws Exception
    {
        Class aClass = Class.forName("test_2021_1_5.反射.Person");
        Constructor constructor = aClass.getDeclaredConstructor(int.class, String.class, Date.class);
        constructor.setAccessible(true);
        constructor.newInstance(15,"张三",new Date());


    }
    @Test
    //一开始我们有可能并不知道参数有几个,顺序是什么,权限是什么,所以可以打印试一试
    public void test07() throws Exception
    {
        Class aClass = Class.forName("test_2021_1_5.反射.Person");
        //获取所有的公共的构造方法
        Constructor[] constructors = aClass.getConstructors();

        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("===================");
        //用getDeclaredConstructors[],可以获取所有的构造方法,包括私有的,保护的
        Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }



    }
}

反射获取类的普通方法

/**
 * 通过反射获取类的方法
 * * Method getMethod(String name,Class...args);
 * 根据方法名和参数类型获得对应的成员方法对象,只能获得public的
 * Method getDeclaredMethod(String name,Class...args);     掌握
 * 根据方法名和参数类型获得对应的成员方法对象,包括public、protected、(默认)、private的
 * Method[] getMethods();
 * 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
 * Method[] getDeclaredMethods();    掌握
 * 获得类中的所有成员方法对象,返回数组,只获得本类的,包括public、protected、(默认)、private
 */
import org.junit.Test;

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

/**
 * 通过反射获取类的方法
 * * Method getMethod(String name,Class...args);
 * 根据方法名和参数类型获得对应的成员方法对象,只能获得public的
 * Method getDeclaredMethod(String name,Class...args);     掌握
 * 根据方法名和参数类型获得对应的成员方法对象,包括public、protected、(默认)、private的
 * Method[] getMethods();
 * 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
 * Method[] getDeclaredMethods();    掌握
 * 获得类中的所有成员方法对象,返回数组,只获得本类的,包括public、protected、(默认)、private
 */
public class demo02 {
    //实例出一个对象,直接调用,获取不到私有的和保护类型的方法
    @Test
    public void test01 () throws Exception
    {
        //第二种方式获取类的字节码对象
        Class personClass = Person.class;
        //获取一个无参的公共的类构造器
        Constructor constructor = personClass.getConstructor();
        //使用构造器创建一个实例
        Person person =(Person) constructor.newInstance();
        //使用实例去调用方法
        person.method1();
        person.method2("张三");
        person.method3(15);
        person.method4(20);
        person.method5("王五");
    }

    //使用反射获取无参方法
    @Test
    public void test02() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //方法一没有参数,传null或者不传都可以
        Method method = personClass.getMethod("method1");
        //传入类的对象,和参数
        method.invoke(p);

    }
    //使用反射获取有参方法
    @Test
    public void test03() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //传入方法的名字,和参数的字节码对象
        Method method2 = personClass.getMethod("method2", String.class);
        method2.invoke(p,"张三");

    }
    @Test
    public void test04() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //传入方法的名字,和参数的字节码对象
        Method method2 = personClass.getMethod("method3", int.class);
        method2.invoke(p,15);

    }
    //使用反射获取返回值类型不为空的
    @Test
    public void test06() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //传入方法的名字,和参数的字节码对象
        Method method2 = personClass.getMethod("method4", int.class);
       int invoke =(int)method2.invoke(p, 15);
        System.out.println(invoke);

    }

    //使用反射获取私有的方法
    @Test
    public void test07() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //传入方法的名字,和参数的字节码对象
        Method method2 = personClass.getDeclaredMethod("method7");
        //设置暴力反射
        method2.setAccessible(true);
        method2.invoke(p);

    }
    //使用反射获取所有的方法
    @Test
    public void test08() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //查询所有的方法

        Method[] method2 = personClass.getDeclaredMethods();
        for (Method method : method2) {
            System.out.println(method);
        }
        System.out.println("===================================================");
        //查询公共的方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

    }

}

反射获取类的变量

/**
 * 通过反射获取类的成员变量
 * Class类中与Field相关的方法
 * Field getField(String name);
 *  根据成员变量名获得对应Field对象,只能获得public修饰
 * Field getDeclaredField(String name);
 *  根据成员变量名获得对应Field对象,包括public、protected、(默认)、private的
 * Field[] getFields();
 * 获得所有的成员变量对应的Field对象,只能获得public的
 * Field[] getDeclaredFields();
 * 获得所有的成员变量对应的Field对象,包括public、protected、(默认)、private的
 */
import org.junit.Test;

import java.lang.reflect.Field;
import java.util.Date;

/**
 * 通过反射获取类的成员变量
 * Class类中与Field相关的方法
 * Field getField(String name);
 *  根据成员变量名获得对应Field对象,只能获得public修饰
 * Field getDeclaredField(String name);
 *  根据成员变量名获得对应Field对象,包括public、protected、(默认)、private的
 * Field[] getFields();
 * 获得所有的成员变量对应的Field对象,只能获得public的
 * Field[] getDeclaredFields();
 * 获得所有的成员变量对应的Field对象,包括public、protected、(默认)、private的
 */
public class demo03 {
    @Test
    //获取public属性
    public void test01() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //获取name变量的的Field对象
        Field name = personClass.getField("name");
        //获取Filed对象的值
        String o = (String)name.get(p);
        System.out.println(o);
    }
    //获取private属性
    @Test
    public  void test02() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //获取私有的变量的Filed对象
        Field age = personClass.getDeclaredField("age");
        //暴力反射
        age.setAccessible(true);
        //获取参数值
        int o =(int) age.get(p);
        System.out.println(o);


    }
    //设置静态变量的值
    @Test
    public  void test03() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //获取私有的变量的Filed对象
        Field date= personClass.getDeclaredField("date");
        //设置变量的值
        date.set(p,new Date());
        System.out.println(Person.date);
    }
//获取所有的变量
    @Test
    public  void test04() throws Exception{
        Class personClass = Person.class;
        Person p = (Person)personClass.newInstance();
        //获取私有的变量的Filed对象
        Field[] fields= personClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("===================================================================");
        //获取public
        Field[] fields1 = personClass.getFields();
        for (Field field : fields1) {
            System.out.println(field);
        }
    }


}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值