java 反射使用简介

前言:

        刚工作那会使用 java 比较实在,主要注重功能的实现,觉得反射很鸡肋;类实现的细节都是可见的,操作起来简单,还非要搞一个反射,莫名其妙;若干年过去,感慨反射真是一个伟大的东西。

1. 初识反射

反射的效果:

  • 可以获取任何一个类的所有属性和方法;
  • 可以修改任何一个对象的所有属性;
  • 可以调用任何一个对象的所有方法;

工作中大多接触的是业务代码,亲手写反射的机会不多;但是工作中用的好多框架都可以看到反射的影子,例如:注解;框架代码要求很高的普适性,需要在屏蔽类的基础上进行操作,跟反射不谋而合。

2. Class

  • Class可以说是反射能够实现的基础
  • class关键字是在声明java类时使用的;而Class 是java JDK提供的一个类,完整路径为 java.lang.Class
  • 对于每一种类,Java虚拟机都会初始化出一个Class类型的实例,每当我们编写并且编译一个新创建的类就会产生一个对应Class对象,并且这个Class对象会被保存在同名.class文件里。
  • 当我们new一个新对象或者引用静态成员变量时,Java虚拟机(JVM)中的类加载器系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。
    构造器是私有的,只有JVM才可以调用这个构造函数创建Class的对象
  • 每个class(注意class是小写,代表普通类)类,无论创建多少个实例对象,在JVM中都对应同一个Class对象。

3. 获取 Class 三种方式

这里以 Person 类为基础进行反射的操作:

package anno;

public class Person {
    public String name;
    private int age;

    public Person(String name, int age) {
        this.age = age;
        this.name = name;
        System.out.println("new a person, name is " + name + ", age is " + age);
    }

    @Override
    public String toString() {
        return "name: " + name + ", age: " + age;
    }

}

获取 Class 的三种方式如下:

        Class p1 = Person.class;
        Class p2 = Class.forName("anno.Person");

        Person person = new Person("jonny", 20);
        Class p3 = person.getClass();

4. 操作属性

1)获取属性

方法有四个,如下:

//获取指定的变量(只要是声明的变量都能获得,包括private)
getDeclaredField(String name)

//获取指定的变量(只能获得public的)
getField(String name)

//获取所有声明的变量(包括private)
getDeclaredFields()

//获取所有的public变量
getFields()

使用举例:

        Person person = new Person("jonny", 20);
        Class p3 = person.getClass();

        Field[] fields = p3.getDeclaredFields();
        System.out.println("*******反射获取类的字段以及字段相关信息*******");
        for (Field field : fields) {
            System.out.println("属性字段:" + field.getName() + ", 类型:" + field.getType() + ",修饰符:" + Modifier.toString(field.getModifiers()));
        }

打印结果如下:

new a person, name is jonny, age is 20
*******反射获取类的字段以及字段相关信息*******
属性字段:name, 类型:class java.lang.String,修饰符:public
属性字段:age, 类型:int,修饰符:private

2)操作属性

        Person person = new Person("jonny", 20);
        Class p3 = person.getClass();

        try {
            System.out.println("*******反射获取类public字段的值并修改*******");
            Field fieldName = p3.getField("name");
            String name = (String) fieldName.get(person);
            System.out.println("从反射获取的name值:" + name);
            fieldName.set(person,"jenny");
            System.out.println(person.toString());

            System.out.println("*******反射获取类private字段的值并修改*******");
            Field fieldAge = p3.getDeclaredField("age");
            fieldAge.setAccessible(true); // 私有属性操作需要
            int age = (int) fieldAge.get(person);
            System.out.println("从反射获取的age值:" + age);
            fieldAge.set(person,18);
            System.out.println(person.toString());
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

打印结果如下:

new a person, name is jonny, age is 20
*******反射获取类public字段的值并修改*******
从反射获取的name值:jonny
name: jenny, age: 20
*******反射获取类private字段的值并修改*******
从反射获取的age值:20
name: jenny, age: 18

5. 操作构造方法

1)获取构造方法

//获取指定构造函数,参数parameterTypes为构造方法的参数类型
getDeclaredConstructor(Class<?>... parameterTypes)

//获取指定public构造函数,参数parameterTypes为构造方法的参数类型
getConstructor(Class<?>... parameterTypes)

//获取所有声明的构造方法
getDeclaredConstructors()

//获取所有的public构造方法
getConstructors()
        Class p2 = Class.forName("anno.Person");
        Constructor[] constructors = p2.getDeclaredConstructors();
        System.out.println("构造方法数量:" + constructors.length);
        for (Constructor constructor : constructors) {
            System.out.print("构造函数修饰符:" + Modifier.toString(constructor.getModifiers()) + ", 参数:");
            Class[] parameterTypes = constructor.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.print(parameterType.getName() + ",");
            }
        }

打印结果如下:

new a person, name is jonny, age is 20
构造方法数量:1
构造函数修饰符:public, 参数:java.lang.String,int,

2)用构造方法获取实例

        Class p2 = Class.forName("anno.Person");

        Class[] parameterArr = {String.class, int.class};

        Constructor constructor = p2.getDeclaredConstructor(parameterArr);
        Person newPerson = (Person) constructor.newInstance("jenny", 19);

打印结果如下:

new a person, name is jenny, age is 19

6.操作方法

1)相关方法

//根据方法名获得指定的方法,参数parameterTypes为方法的参数类型
getDeclaredMethod(String name, Class<?>... parameterTypes)

//根据方法名获取指定的public方法
getMethod(String name, Class<?>... parameterTypes)

//获取所有声明的方法
getDeclaredMethods()

//获取所有的public方法
getMethods()

//获取目标方法返回类型对应的Class对象
getReturnType()或者 getGenericReturnType()

// 执行方法
invoke()

2)执行方法

        Person person = new Person("jonny", 20);
        Class p3 = person.getClass();

        Class[] parameterArr = {};
        Method method = p3.getDeclaredMethod("toString",parameterArr);
        String resultStr = (String) method.invoke(person, parameterArr);
        System.out.println(resultStr);

打印结果如下:

new a person, name is jonny, age is 20
name: jonny, age: 20

7.注解

注解这块单独写

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值