澳门新葡萄京娱乐场 2

Java反射在JVM的实现

1. 什么是Java反射,有如何用?

反射使程序代码能够对接装载到JVM中的类的中间消息,允许在编写与实行时,并非源代码中选定的类合营的代码,是以开荒效率换运营作用的一种花招。那使反射成为营造灵活应用的第一工具。

反射能够:

  1. 调用一些民用方法,完成黑科技(science and technology卡塔尔(قطر‎。举个例子双卡短信发送、设置意况栏颜色、自动挂电话等。
  2. 落到实处种类化与反连串化,举例PO的ORM,Json深入深入分析等。
  3. 得以实现跨平台宽容,举个例子JDK中的SocketImpl的贯彻
  4. 经过xml或表明,达成依据注入(DI卡塔尔国,申明管理,动态代理,单元测量检验等效果。举例Retrofit、Spring可能Dagger

  5. Java Class文件的协会


在*.class文件中,以Byte流的样式进行Class的积累,通过一雨后苦笋Load,Parse后,Java代码实际上能够映射为下图的构造体,这里能够用javap命令或许IDE插件实行查看。

typedef struct {
    u4             magic;/*0xCAFEBABE*/
    u2             minor_version; /*网上有表可查*/
    u2             major_version; /*网上有表可查*/
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    //重要
    u2             fields_count;
    field_info     fields[fields_count];
    //重要
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}ClassBlock;
  • 常量池(constant
    pool卡塔尔国:肖似于C中的DATA段与BSS段,提供常量、字符串、方法名等值或许符号(能够用作偏移定值的指针)的存放
  • access_flags: 对Class的flag修饰

  typedef enum {
      ACC_PUBLIC = 0x0001,
      ACC_FINAL = 0x0010,
      ACC_SUPER = 0x0020,
      ACC_INTERFACE = 0x0200,
      ACC_ACSTRACT = 0x0400
  }AccessFlag
  • this class/super class/interface:
    二个尺寸为u2的指针,指向常量池中真正之处,将在Link阶段实行标志解引。

  • filed: 字段音讯,布局体如下

  typedef struct fieldblock {
     char *name;
     char *type;
     char *signature;
     u2 access_flags;
     u2 constant;
     union {
         union {
             char data[8];
             uintptr_t u;
             long long l;
             void *p;
             int i;
         } static_value; 
         u4 offset;
     } u;
  } FieldBlock;

method: 提供descriptor, access_flags, Code等索引,并照准常量池:

它的构造体如下,详细在这里

  method_info {
      u2             access_flags;
      u2             name_index;
      //the parameters that the method takes and the 
      //value that it return
      u2             descriptor_index;
      u2             attributes_count;
      attribute_info attributes[attributes_count];
  }

以上具体内容能够参见

  1. JVM文档
  2. 周志明的《深远了然Java设想机》,少见的国内精品图书
  3. 有些国外教程的解析

The implementation of Java reflection in JVM

一、五个概念

  • 编写翻译型语言:程序在试行在此之前需求将源代码编写翻译成机器语言,再由机器运转搭乘飞机器码(二进制)。像C/C++、Delphi等都以归属编译型语言,编写翻译型语言必要凭仗编写翻译器,通过编写翻译器将源代码编写翻译成与运转平台对应的机器码,运营时无需重新讲解运作,所以程序实施功能高,但因为编写翻译器编写翻译的机器码与运作平台相关,所以跨平台性差。
  • 解释性语言:相对编写翻译型语言,没有必要事情发生前编译,以文件格局存款和储蓄程序代码,在运营程序时,必得先由解释器解释再运转,每实行贰回就要翻译三遍,效用非常的低,像JavaScript,VBScript,Python,Ruby等都是解释型语言。

3. Java Class加载的经过

Class的加载首要分为两步

  • 第一步通过ClassLoader举办读取、连结操作
  • 其次步实行Class的<clinit>()初始化。

二、JAVA归于哪一类语言?

  • 对此Java语言,Java程序首先通过编写翻译器编写翻译成.class文件,也正是字节码,并非是能够直接由机器间接运营的地头机器码,假诺在windows平台上运行,则字节码通过windows平台上的JVM(JAVA虚构机卡塔尔国举办分解施行。假诺运维在linux平台上,字节码则透过linux平台上的java虚构机举行讲明施行。所以JAVA语言的跨平台湾特务性是通过JVM的跨平台湾特务性实现的,若无JVM,则不可能开展跨平台。所以JAVA语言兼具解释性语言和编写翻译型语言的表征,可以说是一种“半编译半解释”履行的语言。综合以上性情,编译型语言和解释型语言的归类就不太规范了。
  • 可以把JAVA语言划分到编写翻译型语言中,因为编写翻译的庐山真面目目便是把一种对峙高等的语言调换为另二个相对低等的言语,而由.java文件->.class文件的编写翻译已经知足了这特性情。

3.1. Classloader加载经过

ClassLoader用于加载、连接、缓存Class,能够透过纯Java或然native进行贯彻。在JVM的native代码中,ClassLoader内部掩护着三个线程安全的HashTable<String,Class>,用于贯彻对Class字节流解码后的缓存,假使HashTable中早原来就有了缓存,则直接回到缓存;反之,在赢得类名后,通过读取文件、互连网上的class字节流反种类化为JVM中native的C构造体,接着malloc内部存款和储蓄器,并将指针缓存在HashTable中。

上面是非数组情状下ClassLoader的流水生产线

  • find/load: 将文件反种类化为C构造体。

澳门新葡萄京娱乐场 1

Class反类别化的流程

  • link:
    依据Class布局体常量池进行标志的解引。举个例子对象总结内部存款和储蓄器空间,成立方法表,native
    invoker,接口方法表,finalizer函数等专门的学业。

本文目录

三、为什么要选用反射?

  1. 大家清楚,JAVA程序需求经过编写翻译器编写翻译成.class文件,再由JVM解释运作,那么些Class对象承载了那几个类的具有音信,包罗父类、接口、构造函数、方法属性等,那一个.class文件在运维从前会被ClassLoader加载到虚构机中,当二个类被设想机加载之后,JVM就能够在内部存款和储蓄器中自行发出多个Class对象。大家通过new的花样创设对象实际上就是经过这几个Class“模板”来创立实例对象,而以此进度对大家来讲是晶莹的,具体落到实处细节大家不学无术。
  2. 从以上分析可以预知,大家编辑的JAVA类供给经过编写翻译之后再由JVM解释试行,JVM解释推行的是我们编辑的JAVA类生成的应和的.class文件,因为大家心有余而力不足在程序运转的进程中订正.class文件,所以,大家编辑的JAVA类,到了程序真的运维的时候是无计可施订正的,除非大家纠正JAVA类,然后在重新编写翻译运维。那么我们怎么在程序运营的修正类的连锁信息吗?那时JVM相当于给我们提供了多少个接口,让我们经过反射来修正已经编译好的JAVA类。是一种以支出功能换运维功效的手法。
  3. 此情此景:大家要求在程序运营的历程中动态变化三个类的实例,不过大家在程序运维以前不可能获知那几个JAVA类的其余新闻,那也等于说我们在程序中不可能定义那些类,也就不可能透过new方法来变化对应的实例,也无从再编写翻译的长河生成对应的.class文件,那大家仍是可以去动态的加载那么些类并为那个类生成对应的实例吗?
  4. 反射的劳作规律正是依据和反光相关的几个主题类:java.lang.Class:Class类;java.lang.reflect.Constructor:构造器类;java.lang.reflect.Method:方法类;java.lang.reflect.Field:属性类。java.lang.Class是三个Java类,世襲自Object类。Class类是贰个java中的泛型类型。Class类是日常类和接口的愈加抽象,而Class类的每一个实例则表示运转中的三个类。Class类的布局函数是个人的,无法透过new关键字来创制Class类的实例。只好通过JVM来调用它来布局贰个Class实例。在程序运营时动态访谈和改进任何类的行事和情景。

3.2. 开首化进程

当ClassLoader加载Class甘休后,将开展Class的初阶化操作。主要实践<clinit()>的静态代码段与静态变量(决计于源码顺序)。

public class Sample {
  //step.1
  static int b = 2;
  //step.2
  static {
    b = 3;
  }

  public static void main(String[] args) {
    Sample s = new Sample();
    System.out.println(s.b);
    //b=3
  }
}

澳门新葡萄京娱乐场,实际参照他事他说加以考查如下:

  • When and how a Java class is loaded and
    initialized?
  • The Lifetime of a
    Type

在变成开始化后,正是Object的布局<init>了,本文暂不研商。

  1. 什么样是Java反射,有何样用?
  2. Java Class文件的组织
  3. Java Class加载的长河
  4. 反射在native的实现
  5. 附录

四、反射能做什么样?

  1. 经过反射大家得以获取叁个类的装有信息,如访问四个类中的全部属性和格局,包罗拜见权限受节制的性质和方法(注解为private或protected的习性和办法),通过反射我们能够访问三个对象的随机八本质量和措施。换句话说,JVM能够加载一个运营时才获有名称的.class文件,然后获知其完全构造,并生成其对象实体、或对其田野先生s(变量卡塔尔国设置,或调用其methods(方法卡塔尔。
  2. 反射犹如下效果:①操作因访谈权限限定的习性和艺术;②兑现自定义表明,如依附注入(DI),评释管理,动态代理,单元测验等功用。比如Retrofit,Spring,Dagger。;③动态加载第三方jar包;④按需加载类。⑤兑现体系化与反类别化,比如PO的ORM,Json深入分析等。⑥得以达成跨平台包容,比方JDK中的SocketImpl的落实。

4. 反射在native的实现

反射在Java中能够直接调用,不过最后调用的仍为native方法,以下为主流反射操作的得以完成。


五、反射在native中的达成

  1. Class.forName的实现
    Class.forName能够通过包名寻觅Class对象,举例Class.forName(“java.lang.String”卡塔尔。
    在JDK的源码达成中,能够发掘最终调用的是native方法forName0(卡塔尔国,它在JVM中调用的实乃findClassFromClassLoader(State of Qatar,原理与ClassLoader的流水生产线相近。
  2. getDeclaredFields的实现
    在JDK源码中,能够清楚class.getDeclaredFields(卡塔尔国方法其实调用的是native方法getDeclaredFields0(State of Qatar,它在JVM首要完结步骤如下:

    依照Class布局体消息,获取田野(field卡塔尔国_count与fields[]字段,那么些字段早就在load进程中被放入了
    ② 根据field_count的高低分配内部存款和储蓄器、创制数组
    ③ 将数组进行forEach循环,通过田野s[]中的新闻依次成立Object对象
    ④ 再次来到数组指针
    重大慢在如下方面:1.创办、总结、分配数组对象;2.对字段进行巡回赋值。
  3. Method.invoke的实现
    以下为无同步、无特别的气象下调用的步子:
    ①创建Frame
    ②假若目的flag为native,交给native_handler实行管理
    ③在frame中执行java代码
    ④弹出Frame
    ⑤重返实行结果的指针
    一字千金慢在如下方面:1.供给完全推行ByteCode而缺少JIT等优化;2.反省参数相当多,那一个自然能够在编写翻译器恐怕加载时做到。
  4. class.newInstance的实现
    ①检验权限、预分配空间尺寸等参数
    ②开立Object对象,并分配空间
    ③透过Method.invoke调用结构函数(<init>(State of Qatar卡塔尔(قطر‎
    ④返回Object指针
    最首要慢在如下方面:1.参数检查不能够优化依旧疏漏;2.<init>(卡塔尔(قطر‎的查表;3.Method.invoke本人耗费时间。

4.1. Class.forName的实现

Class.forName能够由此包名找寻Class对象,比如Class.forName("java.lang.String")
在JDK的源码落成中,能够窥见最后调用的是native方法forName0(),它在JVM中调用的莫过于是findClassFromClassLoader(),原理与ClassLoader的流水生产线同样,具体达成已经在上边介绍过了。

1. 怎样是Java反射,有啥用?

反射使程序代码能够对接装载到JVM中的类的中间音讯,允许在编写翻译时与实行时,实际不是源代码中选定的类合营的代码,简单来讲,就是以支付功能换运营功能的一种手腕。那使反射成为营造灵活利用的主要工具。

反射能够:

  1. 调用一些私家方法,完结黑科技(science and technology卡塔尔(قطر‎。譬如双卡短信发送、设置景况栏颜色、自动挂电话等。
  2. 福寿绵绵连串化与反连串化,比方PO的ORM,Json分析等。
  3. 贯彻跨平台包容,举例JDK中的SocketImpl的落实
  4. 透过xml或注明等元数据,达成依赖注入(DI卡塔尔(قطر‎,注脚管理,动态代理,单元测量试验等功用。例如Retrofit、SSH框架可能Dagger

  5. Java Class文件的架构


在*.class文件中,以Byte流的花样张开Class的仓储,通过一三种Load,Parse后,Java代码实际上能够映射为下图的C布局体,这里能够用javap一声令下恐怕IDE插件举办查看。

typedef struct {
    u4             magic;/*0xCAFEBABE*/
    u2             minor_version; /*网上有表可查*/
    u2             major_version; /*网上有表可查*/
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    //重要
    u2             fields_count;
    field_info     fields[fields_count];
    //重要
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}ClassBlock;
  • 常量池(constant
    poolState of Qatar:相符于C中的DATA段与BSS段,提供常量、字符串、方法名等值恐怕符号(能够看成偏移定值的指针)的寄存

  • access_flags: 对Class的flag修饰

      typedef enum {
          ACC_PUBLIC = 0x0001,
          ACC_FINAL = 0x0010,
          ACC_SUPER = 0x0020,
          ACC_INTERFACE = 0x0200,
          ACC_ACSTRACT = 0x0400
      }AccessFlag
    
  • this class/super class/interface:
    二个尺寸为u2的指针,指向常量池中确实的地点,将要Link阶段举办标志解引。

  • filed: 字段新闻,布局体如下

    typedef struct fieldblock {
       char *name;
       char *type;
       char *signature;
       u2 access_flags;
       u2 constant;
       union {
           union {
               char data[8];
               uintptr_t u;
               long long l;
               void *p;
               int i;
           } static_value; 
           u4 offset;
       } u;
    } FieldBlock;
    
  • method: 提供descriptor, access_flags, Code等索引,并针对常量池:

    它的构造体如下,详细在这里

      method_info {
          u2             access_flags;
          u2             name_index;
          //the parameters that the method takes and the 
          //value that it return
          u2             descriptor_index;
          u2             attributes_count;
          attribute_info attributes[attributes_count];
      }
    

上述具体内容能够仿效

  1. JVM文档
  2. 周志明的《深远驾驭Java设想机》,少见的境内精品图书
  3. 一部分海外教程的解析

六、反射为何影响属性?

  1. 前边已经谈到,JAVA程序在运营以前要求经过编写翻译,然后通过ClassLoader加载到JVM中,而类加载分为:加载->验证->希图->拆解深入分析->开首化多个级次,那个都以在运转期以前产生的,反射慢就慢在把装载期做的业务搬到了运营期,也正是说在接受反射时,要求在运路程序在此之前把类的加载进度举行壹回。(解释正确与否心中无数)另一种说法是:编写翻译器无法对反射相关的代码做优化。在Stackoverflow上认为反射超级慢的工程师首要犹如下意见:1.表明等防范代码过于繁缛,这一步本来在link阶段,未来却在测算时举办认证;2.生精粹多临时对象,变成GC与计算时间消耗;3.是因为缺乏上下文,遗失了看不完运作时的优化,举个例子JIT(它能够看成JVM的主要性测评标准之一卡塔尔.

4.2. getDeclaredFields的实现

在JDK源码中,可以领略class.getDeclaredFields()方法其实调用的是native方法getDeclaredFields0(),它在JVM主要实现步骤如下

  1. 遵照Class布局体信息,获取field_countfields[]字段,那几个字段早就在load进程中被放入了
  2. 根据field_count的深浅分配内部存款和储蓄器、成立数组
  3. 将数组进行forEach循环,通过fields[]中的音信依次创制Object对象
  4. 归来数组指针

器重慢在如下方面

  1. 创建、总括、分配数组对象
  2. 对字段实行巡回赋值

3. Java Class加载的进度

Class的加载首要分为两步

  • 率先步通过ClassLoader实行读取、连结操作
  • 第二步实行Class的<clinit>()初始化。

4.3. Method.invoke的实现

以下为无同步、无丰硕的景色下调用的步骤

  1. 创建Frame
  2. 固然指标flag为native,交给native_handler进行拍卖
  3. 在frame中执行java代码
  4. 弹出Frame
  5. 归来实施结果的指针

关键慢在如下方面

  1. 亟需完全实施ByteCode而缺点和失误JIT等优化
  2. 自己斟酌参数超多,这么些本来能够在编写翻译器或然加载时成功

3.1. Classloader加载进度

ClassLoader用于加载、连接、缓存Class,能够经过纯Java或许native实行落到实处。在JVM的native代码中,ClassLoader内部维护着三个线程安全的HashTable<String,Class>,用于贯彻对Class字节流解码后的缓存,假如HashTable中曾经有了缓存,则直接重回缓存;反之,在收获类名后,通过读取文件、互联网上的class字节流反类别化为JVM中native的C布局体,接着malloc内存,并将指针缓存在HashTable中。

下边是非数组境况下ClassLoader的流水生产线

  • find/load: 将文件反连串化为C布局体。

澳门新葡萄京娱乐场 2

Class反体系化的流程

  • link:
    依据Class布局体常量池进行标识的解引。举例对象计算内部存款和储蓄器空间,创设方法表,native
    invoker,接口方法表,finalizer函数等专门的学业。

4.4. class.newInstance的实现

  1. 质量评定权限、预分配空间尺寸等参数
  2. 开创Object对象,并分配空间
  3. 透过Method.invoke调用布局函数(<init>())
  4. 返回Object指针

入眼慢在如下方面

  1. 参数检查无法优化还是脱漏
  2. <init>()的查表
  3. Method.invoke本身耗费时间

3.2. 初叶化进程

当ClassLoader加载Class甘休后,将打开Class的初叶化操作。重要施行<clinit()>的静态代码段与静态变量(决议于源码顺序),下边正是一个大面积的笔试题。

public class Sample {
  //step.1
  static int b = 2;
  //step.2
  static {
    b = 3;
  }

  public static void main(String[] args) {
    Sample s = new Sample();
    System.out.println(s.b);
    //b=3
  }
}

实际参谋如下:

  • When and how a Java class is loaded and
    initialized?
  • The Lifetime of a
    Type

在形成开头化后,正是Object的结构方法<init>了,本文暂不切磋。

5. 附录

4. 反射在native的实现

在打听上文的幼功后,终于得以商讨反射了。反射在Java中可以直接通过JDK提供的秘籍调用,可是最后底层调用的仍然是被映射到native方法,以下为主流JVM反射操作的兑现。

5.1. JVM与源码阅读工具的抉择

初次学习JVM时,不建议去看Android
阿特、Hotspot等重量级JVM的完结,它里面的防范代码非常多,还会有android与libcore、bionic库紧凑耦合,以致分层、内联以至能把编写翻译器的语义深入分析绕进去,因而找三个教学用的、嵌入式小型的JVM有助于节约自己的时刻。因为之前折腾过OpenWrt,听过有大神推荐过jamvm,独有不到200个源文件,特别切合学习。

在工具的拈轻怕重上,个人推举SourceInsight。相比了某个个工具clion,vscode,sublime,sourceinsight,独有sourceinsight对索引、符号表的解析最纯粹。

4.1. Class.forName的实现

  • 介绍
    Class.forName能够透过包名搜索Class对象,举例对String的加载就是Class.forName("java.lang.String")
    此方式最直观的选用正是Spring的IOC了。通过张开Beans的XML描述,Spring就足以经过反射找到这几个类,并透过下文就要讲的class.newInstance完结指标的早先化。通过IOC,无需展开手动装配,那样宏大地下跌了测验难度,有助于合作编制程序。

  • 底层实现
    在JDK的源码达成中,能够窥见调用栈的末段调用的是native方法forName0(),它在JVM中调用的C代码实际是findClassFromClassLoader(),原理与上文ClassLoader的流水线相符,没悟出照旧那样轻便。

5.2. 关于多少个ClassLoader

参考这里

ClassLoader0:native的classloader,在JVM中用C写的,用于加载rt.jar的包,在Java中为空引用。

ExtClassLoader: 用于加载JDK中额外的包,日常不怎么用

AppClassLoader: 加载自个儿写的只怕援引的第三方包,那个最见怪不怪

事例如下

//sun.misc.Launcher$AppClassLoader@4b67cf4d
//which class you create or jars from thirdParty
//第一个非常有歧义,但是它的确是AppClassLoader
ClassLoader.getSystemClassLoader();
com.test.App.getClass().getClassLoader();
Class.forName("ccom.test.App").getClassLoader()

//sun.misc.Launcher$ExtClassLoader@66d3c617
//Class loaded in ext jar
Class.forName("sun.net.spi.nameservice.dns.DNSNameService")

//null, class loaded in rt.jar
String.class.getClassLoader()
Class.forName("java.lang.String").getClassLoader()
Class.forName("java.lang.Class").getClassLoader()
Class.forName("apple.launcher.JavaAppLauncher").getClassLoader()

最后便是getContextClassLoader(),它在汤姆cat中选用,通过设置二个权且变量,能够向子类ClassLoader去加载,并不是信托给ParentClassLoader

ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
    // call some API that uses reflection without taking ClassLoader param
} finally {
    Thread.currentThread().setContextClassLoader(originalClassLoader);
}

终极还可能有局地自定义的ClassLoader,达成加密、压缩、热铺排等功能,这些是大帽山,晚点再开。

4.2. getDeclaredFields的实现

在JDK源码中,Class的class.getDeclaredFields()办法其实调用的是native方法getDeclaredFields0(),它在JVM主要落成步骤如下

  1. 听别人说Class布局体新闻,获取field_countfields[]字段,那一个字段早就在load进程中被放入了
  2. 根据field_count的大小分配内部存款和储蓄器、创制数组
  3. 将数组进行forEach循环,通过fields[]中的音讯依次成立Object对象
  4. 归来数组指针Object[]

此部分的反射首要慢在如下方面

  1. 始建、计算、分配数组对象
  2. 对字段进行巡回赋值

5.3. 反光是不是慢?

在Stackoverflow上感觉反射一点也不快的程序员第一犹如下意见

  1. 证实等堤防代码过于繁缛,这一步本来在link阶段,未来却在计算时进行认证
  2. 发生比比较多有时对象,变成GC与计算时间消耗
  3. 出于贫乏上下文,错失了累累周转时的优化,譬如JIT(它能够看作JVM的显要评测规范之一卡塔尔

自然,今世JVM亦非那几个慢了,它能够对反射代码举办缓存以致因而艺术计数器相似达成JIT优化,所以反射不必然慢。

更首要的是,比很多场合下,你和煦的代码才是节制造进程序的瓶颈。因而,在付出功效远高于运转成效的的底子上,大胆运用反射,放心开辟吧。

4.3. Method.invoke的实现

以下为无同步、无不胜的景色下调用的步子

  1. 创建Frame
  2. 举例目的flag为native,交给native_handler进行拍卖
  3. 在frame中解释java代码
  4. 弹出Frame
  5. 回来推行结果的指针

关键慢在如下方面

  1. 急需完全奉行ByteCode而缺乏JIT等优化
  2. 反省参数很多,也正是防备代码过度,那么些检查本来能够在编写翻译器或许加载时成功

参谋文献

4.4. class.newInstance的实现

得以达成情势如下:

  1. 检查测量检验权限、预分配空间尺寸等参数
  2. 始建Object对象,并分配空间
  3. 透过Method.invoke调用布局函数(<init>())
  4. 返回Object指针

要害慢在如下方面

  1. 参数检查无法优化依旧疏漏
  2. <init>()的查表
  3. Method.invoke自身耗费时间

5. 附录

5.1. JVM与源码阅读工具的接收

首先学习JVM时,不提出去看Android
Art、Hotspot等重量级JVM的落到实处,它里面的看守代码超多,还应该有android与libcore、bionic库紧凑耦合,以至分层、内联以致能把编写翻译器的语义剖析绕进去,由此找叁个讲授用的、嵌入式Mini的JVM有助于节约本人的岁月。因为以前折腾过OpenWrt,听过有大神推荐过jamvm,只有不到200个源文件,非常切合学习。

在工具的挑精拣肥上,个人推举SourceInsight。相比了一点个工具clion,vscode,sublime,唯有sourceinsight对索引、符号表的解析最确切。

5.2. 有关多少个ClassLoader

5.2.1. ClassLoader的信托关系

参考这里,重要犹如下多少个包

ClassLoader0:native的classloader,在JVM中用C写的,用于加载rt.jar的包,在Java中为空引用。

ExtClassLoader: 用于加载JDK中额外的包,日常不怎么用

AppClassLoader: 加载自身写的要么援用的第三方包,那一个最遍布

测验例子如下

//1. sun.misc.Launcher$AppClassLoader@4b67cf4d
//which class you create or jars from thirdParty
//第一个非常有歧义,但是它的确是AppClassLoader
ClassLoader.getSystemClassLoader();
com.test.App.getClass().getClassLoader();
Class.forName("ccom.test.App").getClassLoader()

//2. sun.misc.Launcher$ExtClassLoader@66d3c617
//Class loaded in ext jar
Class.forName("sun.net.spi.nameservice.dns.DNSNameService")

//3. null, class loaded in rt.jar
String.class.getClassLoader()
Class.forName("java.lang.String").getClassLoader()
Class.forName("java.lang.Class").getClassLoader()
Class.forName("apple.launcher.JavaAppLauncher").getClassLoader()

5.2.2. getContextClassLoader

它在汤姆cat中接受,通过安装一个不经常变量,能够向子类ClassLoader去加载,并非信托给ParentClassLoader

ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
    // call some API that uses reflection without taking ClassLoader param
} finally {
    Thread.currentThread().setContextClassLoader(originalClassLoader);
}

5.2.2. 自定义的ClassLoader

自定义的ClassLoader,达成加密、压缩、热布署等职能,
那么些就有苦难言了,纵然你是Android开拓可以参照热点的多少个热修复手艺。

5.3. 反光是或不是慢?

在Stackoverflow上认为反射一点也不快的程序猿首要有如下意见,如若你面试遭受了,能够这么回应

  1. 表明等防范代码过于繁琐,这一步本来在link阶段,现在却在酌量时开展表达
  2. 发生众多一时对象,变成GC与计量时间消耗
  3. 由于缺乏上下文,遗失了成百上千运营时的优化,比如JIT(它能够作为JVM的要紧评测标准之一卡塔尔(قطر‎

金科玉律,小编个人的意见是,今世JVM亦非可怜慢了,它亦可对反射代码进行缓存甚至通过措施流量计同样达成JIT优化,所以反射不自然慢。

更要紧的是,非常多情景下,你本身的代码才是节制造进程序的瓶颈。因而,在支付成效远高于运转效用的的底工上(比方元数据编制程序),大胆应用反射,放心开荒吧。

参照他事他说加以考察文献

  1. http://www.codeceo.com/article/reflect-bad.html
  2. http://blog.csdn.net/lmj623565791/article/details/43452969
  3. http://codekk.com/open-source-project-analysis/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8BJava%20%E6%B3%A8%E8%A7%A3%20Annotation
  4. http://www.trinea.cn/android/java-annotation-android-open-source-analysis/

发表评论

电子邮件地址不会被公开。 必填项已用*标注