趣谈Java反射调用

来源:互联网 发布:一句话网络段子精选 编辑:程序博客网 时间:2024/05/05 02:14

http://mp.weixin.qq.com/s?__biz=MzI3NDA3Njg3Mw==&mid=507802146&idx=1&sn=5fc889e27f480a7e4eccb7d011d4c1d3&scene=23&srcid=0419T28hvOOsyuVMnfQDZhiZ#rd

反射调用是什么?从有限的文档里,我找到了一篇1998的文章《Use Java Reflection》,by Glen McClusKey。这边提到的一个用途是用来动态检测组件(类)的功能。有兴趣的可以查看这边文章:http://www.oracle.com/technetwork/articles/java/javareflection-1536171.html

       抛开上述文章不谈,因为这边文章写得也很早,略显过时。我们根据当下的使用场景来谈谈我对反射调用的理解:

01   理解概念

       我们需要区分普通调用和反射调用的区别。普通调用是客观存在的,一定可以调得到;反射调用这是主观猜测,不一定可以调得到。比如,我们定义一个女性类,开放出来的方法为isAdulty() 和isBeauty()

package com.reflect.test;

class Woman {

    private int age; // 年龄

    private boolean beauty; // 是否漂亮

    

    public boolean isAdulty() {

        return age >= 18;

    }

    

    public boolean isBeauty() {

        return beauty;

    }


    protected int getAge() {

        return age;

    }

}


普通调用,仅可以调用:

Woman woman = new Woman();

woman.isBeauty();

woman.isAdulty();


反射调用,比如我们调用一个不公开的方法,比如getAge这个方法:

public int getAgeByReflect() throws Exception {

    Class<?> clz = Woman.class;

    Object obj = clz.newInstance();

    Method method = clz.getDeclaredMethod("getAge", null);

    method.setAccessible(true);

    return (Integer)method.invoke(obj);

}

我们就可以获得这位女性的年龄这一私密信息。

但是我们尝试getMoney呢?答案当然是获取不到的,但我们程序是可以运行起来的。


02反射流程



如上图所示:

1)绿色流程则是从类名->对象的转换;

2)红色这是该类的成员,从左到右依次:子类,注释,方法,变量

3)黄色这是判断第2步的成员是否是静态变量

4)蓝色则是调用,分为static直接调用,非static则必须传入a这个对象来访问。

03Class


从上面的流程图,可以看出Class 是一切反射的源泉,没有这个,都是空谈,所以,我们重点讲一下如何获取Class对象。

1)通过类名获取

Class clz = Class.forName("com.test.A");

2)通过对象获取

比如我们已经创建了一个对象

A a = new A();

Class clz = a.getClass();

3)通过静态获取

Class clz = A.class;

注意:同时也支持int,boolean,数组之类的,则可以通过如下

Class clz = int.class;

Class clz = int[].class;

04Method

获取了Class 或者对象,接下来我们来看看如何调用方法

1)static方法

public int getAgeByReflect() throws Exception {

    Class<?> clz = Woman.class;

    //Object obj = clz.newInstance();

    Method method = clz.getDeclaredMethod("getAge", null);

    method.setAccessible(true);

    return (Integer)method.invoke(null);

}

2)非static方法

public int getAgeByReflect() throws Exception {

    Class<?> clz = Woman.class;

    Object obj = clz.newInstance();

    Method method = clz.getDeclaredMethod("getAge", null);

    method.setAccessible(true);

    return (Integer)method.invoke(obj);

}


05Field

同样方式,可以访问到变量

1)static变量

public int getAgeFieldByReflect() throws Exception {

    Class<?> clz = Woman.class;

    //Object obj = clz.newInstance();

    Field field = clz.getDeclaredField("age");

    field.setAccessible(true);

    return (Integer)field.get(null);

}


2)非static变量

public int getAgeFieldByReflect() throws Exception {

    Class<?> clz = Woman.class;

    Object obj = clz.newInstance();

    Field field = clz.getDeclaredField("age");

    field.setAccessible(true);

    return (Integer)field.get(obj);

}


06Modifier

限定符,用来修饰用,public、private、static、final等

比如方法,可以通过调用

int modifiers = method.getModifiers();

然后,调用Modifier.isPublic(modifiers); 判断是不是public,true代表是共有方法。同理,对于其他成员也可以使用!


07适用场景

1)Android未公开API

       众所周知,Android系统有一些隐藏的API是不对外开放的,仅限系统APP调用。那么,就可以使用反射调用的机制来访问到这些API。

2)动态插件调用

      现在很多APP为了瘦身,将功能按模块划分,部分模块独立做成插件放至服务器,再动态下发至客户端。APP调用插件的方式便是采用反射调用的方法。目前市面上很多大公司的APP都实现了插件化功能,比如淘宝、手机管家、GO桌面等,这些APP功能复杂,但安装包特别小!

0 0
原创粉丝点击