Java基础之反射

图片 2

1. 怎么着是Java反射,有怎么着用?

反射使程序代码能够对接装载到JVM中的类的内部音信,允许在编排与实行时,并非源代码中选定的类合营的代码,是以开发效能换运营功用的一种花招。那使反射成为营造灵活使用的根本工具。

反射能够:

  1. 调用一些民用方法,完毕黑科学技术。举例双卡短信发送、设置情形栏颜色、自动挂电话等。
  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
    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. 一些国外教程的解析

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(卡塔尔国,原理与ClassLoader的流水生产线同样。
  2. getDeclaredFields的实现
    在JDK源码中,能够掌握class.getDeclaredFields(State of Qatar方法其实调用的是native方法getDeclaredFields0(卡塔尔国,它在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>(卡塔尔(قطر‎卡塔尔
    ④返回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 technologyState of Qatar。比方双卡短信发送、设置情状栏颜色、自动挂电话等。
  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
    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. 一对国外教程的解析

六、反射为何影响属性?

  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
Art、Hotspot等重量级JVM的得以达成,它在那之中的防止代码相当多,还会有android与libcore、bionic库紧凑耦合,以致分层、内联以至能把编写翻译器的语义深入分析绕进去,由此找叁个教学用的、嵌入式Mini的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库紧凑耦合,以至分层、内联以至能把编写翻译器的语义剖判绕进去,由此找三个教学用的、嵌入式小型的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/
You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图