再谈Java反射

在日常开发中尽量不要用反射,如果需要,先考虑通过复制原始类的形式来避免反射,还不行再考虑通过反射。

反射能帮我们做什么?

  1. 反射构建出无法直接访问的类
  2. set或get到无法访问的类变量
  3. 调用不可访问的方法

每个包装器原始数据类型类具有名为 TYPE 的静态字段
int.class 和 Integer.TYPE 指的是同一个类对象。

上一篇我在Java反射札记里说了如何反射一个类,代参实例对象,反射属性和方法。这次我们来看一个开源类库

jOOR 传送门 (https://github.com/jOOQ/jOOR)

我们一起学习下这个库的代码

这个开源库适配了Java6,Java8 和2017年11月份已经发布的Java9,作者在开发这个类库使,借鉴了已有的项目,做了调研和测试。

github上给出的Demo代码段:

String world = on("java.lang.String")  // Like Class.forName()
                .create("Hello World") // Call most specific matching constructor
                .call("substring", 6)  // Call most specific matching substring() method
                .call("toString")      // Call toString()
                .get();  

上述代码采用链式调用,on方法 create方法,call方法内部都是调用的on的重载方法,返回Reflection类,最后的get()内部采用了泛型返回,如下:

/**
 * Get the wrapped object
 *
 * @param <T> A convenience generic parameter for automatic unsafe casting
 */
@SuppressWarnings("unchecked")
public <T> T get() {
    return (T) object;
}

关于泛型的使用,可以查阅之前的两篇:

  1. 重识Java泛型 上
  2. 重识Java泛型 下

在Android项目中,findViewById经过这样封装后,再也不用强转类型了。

类加载机制

JVM里java的类的加载流程图

这部分内容已在:Java反射札记 这篇讲解了,这里不重复了

Loading -> Linking -> Initialization

类一定会初始化的五大情况

  1. 使用new字节码指令创建类的实例,或者使用getstatic、putstatic读取或设置一个静态字段的值(放入常量池中的常量除外),或者调用一个静态方法的时候,对应类必须进行过初始化。

  2. 通过java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则要首先进行初始化。

  3. 当初始化一个类的时候,如果发现其父类没有进行过初始化,则首先触发父类初始化。

  4. 当虚拟机启动时,用户需要指定一个主类(包含main()方法的类),虚拟机会首先初始化这个类。

  5. 使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、RE_invokeStatic的方法句柄,并且这个方法句柄对应的类没有进行初始化,则需要先触发其初始化。

关于第五点,没有接触过

现在通过代码实践来试试看吧

我定义了SuperClass类和SubClass类

SuperClass类

public class SuperClass {

    public static String sValue = "666";

    public static final String HELLO_WORLD = "hello world!";

    static {
        Out.println("SuperClass init");
    }

    public String getContent(){
        return "This is String result";
    }

    public static void setsValue(String value){
        sValue = value;
    }
}

SubClass

public class SubClass extends SuperClass {

    public static String sTemp = "";

    static {
        sTemp = "sub class temp";
        Out.println("Subclass init");
    }

    public void instanceTest(){
        Out.println("instanceTest");
    }
}

测试下第一点,new的时候

/**
 * 类初始化
 */
private static void testVersion1_2() {
    SubClass subClass = new SubClass();
}

输出:

SuperClass init
Subclass init

子类SubClass和SuperClass都经历了类初始化阶段

测试下第一点里提到的引用静态字段时

/**
 * 类初始化3
 */
private static void testVersion1_3() {
    Out.println(SubClass.sTemp);
}

输出:

SuperClass init
Subclass init
sub class temp

再看下这段代码

/**
 * 类初始化1 主动引用/被动引用
 */
private static void testVersion1_1() {
    Out.println(SubClass.sValue);
}

你觉得SubClass类会调用static静态代码块么?

输出:

SuperClass init
666

答案是不会,神奇的一幕,SubClass没有经过类初始化

Java“相等”判定相关方法

我们最熟悉的是instanceof方法,这个是实例对象的方法,判断当前对象是否是某个类的实例。

如果我要比较class类与类之间是否子类关系呢?要比较class对象和一个实例对象呢?

Java反射为我们提供了解决方法

/**
 * 相等判断 除了 instanceof
 */
private static void testVersion2_1() {
    Out.println(SuperClass.HELLO_WORLD);
}

private static void testVersion3_1() {
    boolean isAssignable = SuperClass.class.isAssignableFrom(SuperClass.class);
    Out.println("isAssignable = " + isAssignable);
}

private static void testVersion3_2() {
    SubClass subClass = new SubClass();
    boolean isInstance = SuperClass.class.isInstance(subClass);
    Out.println("isInstance = " + isInstance);
}

说明:使用isInstance,isAssignableFrom是需要注意判断的逻辑关系。比如拿testVersion3_1方法举例,boolean isAssignable = SuperClass.class.isAssignableFrom(SuperClass.class);说的是SuperClass是否是SuperClass的子类啊?isAssignable的布尔值就是答案

参考资料

欢迎关注CodeThings
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 1,220评论 0 2
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 1,051评论 0 4
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,094评论 0 62
  • 春天这早晨,过了上班的点你再起床,那简直就像鬼压床般难受啊。自己一直在叫身旁人的名字,“谁谁谁,拉我一把,拉我起床...
    爱三国的我阅读 154评论 0 0
  • 2018 年1月31日,第94天,第52次记录。 昨晚没继续下雪。 早上有零下二十四度,和老公一起走了两公里,没跑步。
    云更容易阅读 92评论 0 0