利用反射分析类的能力

java.lang.reflect包中有三个类,Field,Method,Constructor,这三个类都有一个叫getName()的方法来返回项目名称。其中他们都有对指定成员/方法,赋值和修改的工具,含declared的表示他们多了一个访问私有域的权限,否则只有访问和操作公有域的权限;可以选择使用哪个构造器,传入参数构造构造器的实例。

Field: 获取成员变量的信息

field 和 field[]类型只能获取public的成员变量,包括父类
getDeclaredFields方法可以获取所有成员变量,不能获取到父类

field 的 getField方法和getDeclaredField 方法都是对指定名称成员变量去获取的
field[] 的 getFields 方法和 getDeclaredFields 方法是获取成员的集合

虽然 getDeclaredField 可以访问 private 成员变量,但是不具有操作它的能力
想要操作它就必须加入一个setAccessible(true)来忽略访问权限
field 中 的 getDeclaredField 中有暴力反射法,可忽略访问权限,调用 setAccessible(true);

		//打印类中的公共的成员变量,包括他继承了的父类的成员变量
        Field[] field = Student.class.getFields();//
        for (Field f : field) {
            System.out.println("公有成员:" + f.getName());
        }

        System.out.println("----------------------");
        
		//打印类中的所有的成员变量,不包括他继承了的父类的成员变量
        Field[] field4 = Student.class.getDeclaredFields();
        for (Field f : field4) {
            System.out.println("所有成员:" + f.getName());
        }

        System.out.println("----------------------");

        Field field2 = Student.class.getField("TeacherName");
        //TeacherName是私有成员,所以要忽略访问权限
        field2.setAccessible(true);
        
        Student st = new Student();
        //get方法获取成员值
        Object oj = field2.get(st);
        System.out.println(oj);
        //set方法修改成员值
        field2.set(st, "Teacher");
        Object oj2 = field2.get(st);
        System.out.println(oj2);

        System.out.println("----------------------");

        Field field3 = Student.class.getField("publicPersonName");
        //publicPersonName是父类的公有成员
        Student st1 = new Student();
        Person ps1 = new Person();
        // set方法设定对象参数是因为有一些成员是继承得到的,下面进行演示
        field3.set(st1, "student");
        field3.set(ps1, "Person");
        //子类的
        Object oj3 = field3.get(st1);
        //父类的
        Object oj4 = field3.get(ps1);
        //输出
        System.out.println(oj3);
        System.out.println(oj4);

        System.out.println("----------------------");

Method:获取成员方法的信息(使用方法和Field的几乎一样)

publlic Object invoke(Object implicitParameter,Object[ ] explicitparamenters)

invoke 的参数和返回值必须是Object类型的,在使用包装器传递基本类型时,基本类型的返回值必须是未包装的。

下面是一个例子:

		Method method4 = studentClass.getMethod("getSalary", int.class);
        int a = (Integer) method4.invoke(st0, 50);
        System.out.println(a);

method4.invoke(st0, 50);调用了

public int getSalary(int salary) {
return salary * 2;
}

返回对象是Object类,实际接收的是Integer类,因此 int a 不能直接接收到这个对象,只要把这个对象向下造型成Integer,就会触发自动拆箱

这就意味着必须进行多次类型转换,这样会使编译器错过检查代码的机会,因此等待测试阶段才会发现这些错误,找到并改正将会很困难。不仅如此,使用反射获得方法指针的代码要比仅仅直接调用方法显得慢一些。

所以,建议仅在必要的时候才使用Method对象,而最好使用接口以及lambda表达式。

特别要重申:建议Java开发者不要使用Method对象的回调功能。使用接口进行回调会使得代码的执行速度更快,更易于维护

		Class<Student> studentClass = Student.class;
		//打印类中的公共的成员方法,包括它的继承到的父类的公共成员方法,返回一个数组
        Method[] methods = studentClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        System.out.println("-------------------------------");
		打印类中的所有的成员方法,不包括它的继承到的父类的公共成员方法,返回一个数组
        Method[] methods2 = studentClass.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(method);
        }

        System.out.println("-------------------------------");

        // getMethod(String name,Class <?> ... parameterTypes)
        // parameterTypes是形参的意思,没有参数就不用输入
        // Java调用方法看的是方法名和参数列表
        // 所以在使用getMethod创建指定方法对象时要加入方法名和参数列表
        Method method0 = studentClass.getMethod("read");// 这里会抛出异常
        System.out.println(method0);

        System.out.println("-------------------------------");

        // 演示暴力反射和有参数的举例
        Method method1 = studentClass.getDeclaredMethod("privateMethod");
        //privateMethod是私有的成员方法
        method1.setAccessible(true);
        Student st0 = new Student();
        // 调用invoke方法使用这个privateMethod方法
        method1.invoke(st0);
        // invoke()方法有两个参数,前者是对象,(如果是继承的方法)是用在父类的身上呢还是自己身上呢,后面是privateMethod方法的参数
        //如果没有参数需要传递,就不需要写东西

        System.out.println("-------------------------------");

        Method method2 = studentClass.getDeclaredMethod("privateMethod", String.class);
        method2.setAccessible(true);
        method2.invoke(st0, "hahahahaha");// 需要传递参数

        System.out.println("-------------------------------");

        Method method3 = studentClass.getMethod("publicStaticMethod", String.class);
        //publicStaticMethod是Student类的静态方法
        // invoke使用静态方法时第一个参数可以忽略,但是不能不填,可以用null代替,比如原来是这样的
        // method3.invoke("st0", "still use args");
        // 现在可以这样写
        method3.invoke(null, "still use args");

Constructor:获取构造器的信息

getConstructors,返回全部公有构造方法
getConstructor,返回公有指定的构造方法
getDeclaredConstructors,返回全部构造方法
getDeclaredConstructor,返回指定的构造方法(部分公共和私有)

		Constructor<Student> constructor = Student.class.getDeclaredConstructor(String.class);
        System.out.println(constructor);

        System.out.println("-------------------------");

        // 尽管此方法返回一个 Constructor<T>对象数组(即此类的构造函数数组)
        // 但此方法的返回类型是 Constructor<?>[],并非 Constructor<T>[]预期的那样

        // Type safety: Unchecked cast from Constructor<?>[] to Constructor<Student>[]
        // 安全性问题,不检查<?>,<?>意思时不确定类型
        //下面这个不使用泛型可以,但是会有一个小警告,就好像Class不使用泛型那样
       	Constructor[] constructor1 = Student.class.getDeclaredConstructors();
        for (Constructor c : constructor1) {
            System.out.println(c);
        }

        System.out.println("-------------------------");

        Constructor<?>[] construstor2 = Student.class.getConstructors();
        for (Constructor<?> c : construstor2) {
            System.out.println(c);
        }

        System.out.println("-------------------------");

        constructor.setAccessible(true);// 暴力反射
        
        //constructor.newInstance(Object[] args)构造一个构造器所属类的新实例,返回一个Object对象,args是提供给构造器的参数
        Object obj = constructor.newInstance("zhangsan");
        //打印这个实例,就是打印使用过构造器后的成员变量
        System.out.println(obj);

        System.out.println("-------------------------");

        // 同理,构造空参,但是这个操作有点麻烦,class类有专门构造空参的方法,也是newInstance(),这是一个老方法了
        Constructor<Student> constructor3 = Student.class.getConstructor();
        Object obj2 = constructor3.newInstance();
        System.out.println(obj2);

        System.out.println("-------------------------");

        // class类的newInstance使用构造空参
        // class类是<T>的,这个类下面有class<?>的方法

        Class<Student> clazz = Student.class;
        Object obj3 = clazz.newInstance();
        System.out.println(obj3);

这三个类有一个方法叫做 getModifiers

int getModifiers() 返回一个用于描述构造器,方法或域的修饰符的整数值,划重点:一个

使用Modifier类中的 isPublic,isPrivate,isFinal 判断它是否是 public,private 还是 final

使用Modifier类的静态方法 Modifier.toString(调用getModifiers后返回的数值);可以翻译出这个修饰符是什么

 		Class studentClass = Student.class;

        int modifier = studentClass.getModifiers();
        String modifierString = Modifier.toString(modifier);
        System.out.println(modifier + " is " + modifierString);

        int field = studentClass.getDeclaredField("teacherName").getModifiers();
        // 不能使用getField("teacherName"),因为它没有访问私有域的权限
        System.out.println("成员\"teacherName\" is " + Modifier.toString(field));

        int method = studentClass.getDeclaredMethod("privateMethod", String.class).getModifiers();
        System.out.println("方法\"privateMethod\" is " + Modifier.toString(method));

        int constructor = studentClass.getDeclaredConstructor(String.class).getModifiers();
        System.out.println("构造方法 is " + Modifier.toString(constructor));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值