Android --- 第九期 面试题

每日分享Android面试题

1、类的加载过程,Person person = new Person();为例进行说明?

  1. 因为new用到了Person.class,所以会先找到Person.class文件,并加载到内存中;
  2. 执行该类中的static代码块,如果有的话,给Person.class类进行初始化;
  3. 在堆内存中开辟空间分配内存地址;
  4. 在堆内存中建立对象的特有属性,并进行默认初始化;
  5. 对属性进行显示初始化;
  6. 对对象进行构造代码块初始化;
  7. 对对象进行与之对应的构造函数进行初始化;
  8. 将内存地址付给栈内存中的p变量

2、类的加载机制是怎么样的呢?

  1. Java程序,都是由若干个.class文件组织而成的一个完整的Java应用程序,

  2. 当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能

  3. 而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常

  4. 而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的

  5. 从而只有class文件被载入到了内存之后,才能被其它class所引用

  6. 所以ClassLoader就是用来动态加载class文件到内存当中用的。

  7. ClassLoader使用的是双亲委托模型来搜索类

3、Android类加机制是什么样的呢?(热更新的机制是什么样的呢,hotFix\andFix机制是什么样的呢)?

  1. 对于Android而言,最终的apk文件包含的是dex类型的文件

  2. dex文件是将class文件重新打包

  3. 打包的规则又不是简单地压缩,而是完全对class文件内部的各种函数表,变量表进行优化,产生一个新的文件,即dex文件。

  4. 因此加载这种特殊的Class文件就需要特殊的类加载器DexClassLoader

  5. 热更新就是把多个dex文件塞入到app的classloader之中,但是android dex拆包方案中的类是没有重复的,如果classes.dex和classes1.dex中有重复的类,当用到这个重复的类的时候,系统就会选择其中一个类。

  6. 一个ClassLoader可以包含多个dex文件,每个dex文件是一个Element,多个dex文件排列成一个有序的数组dexElements,当找类的时候,会按顺序遍历dex文件,然后从当前遍历的dex文件中找类,如果找类则返回,如果找不到从下一个dex文件继续查找。理论上,如果在不同的dex中有相同的类存在,那么会优先选择排在前面的dex文件的类

  7. 在此基础上,我们构想了热补丁的方案,把有问题的类打包到一个dex(patch.dex)中去,然后把这个dex插入到Elements的最前面,当然系统就就会选择我们要更新的类了

  8. 当然每个热更新框架都会有差异

  9. 比如说QZone就是严格按照上述思路进行的

  10. 而hotFix\andFix采用native hook的方式,这套方案直接使用dalvik_replaceMethod替换class中方法的实现。由于它并没有整体替换class, 而field在class中的相对地址在class加载时已确定,所以AndFix无法支持新增或者删除filed的情况(通过替换init与clinit只可以修改field的数值)。Andfix可以支持的补丁场景相对有限,仅仅可以使用它来修复特定问题。

  11. 微信Tinker就要高明一些,在编译时通过新旧两个Dex生成差异path.dex。在运行时,将差异patch.dex重新跟原始安装包的旧Dex还原为新的Dex。这个过程可能比较耗费时间与内存,所以我们是单独放在一个后台进程:patch中。为了补丁包尽量的小,微信自研了DexDiff算法,它深度利用Dex的格式来减少差异的大小。当然看起来很美好的总有些差强人意的事情出现,比如tinker对小米的支持就不太好。

4、追问2双亲机制原理是什么样的呢?

  1. ClassLoader使用的是双亲委托模型来搜索类的

  2. 每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系

  3. 虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

  4. 当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的

  5. 首先由最顶层的类加载器Bootstrap ClassLoader试图加载

  6. 如果没加载到,则把任务转交给Extension ClassLoader试图加载

  7. 如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。

  8. 如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。

  9. 否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

5、为什么要使用双亲委托这种模型呢?

  1. 因为这样可以避免重复加载

  2. 当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。

  3. 考虑到安全因素,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患

  4. 而双亲委托的方式,就可以避免这种情况

  5. 因为String已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载

  6. 所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。

6、JVM在搜索类的时候,又是如何判定两个class是相同的呢?

  1. JVM在判定两个class是否相同时,不仅要判断两个类名是否相同

  2. 而且要判断是否由同一个类加载器实例加载的。

  3. 只有两者同时满足的情况下,JVM才认为这两个class是相同的。

  4. 就算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载

  5. JVM也认为不相同。

  6. 比如网络上的一个Java类Glide

  7. javac编译之后生成字节码文件Glide.class

  8. ClassLoaderA和ClassLoaderB这两个类加载器并读取了Glide.class文件

  9. 并分别定义出了java.lang.Class实例来表示这个类

  10. 对于JVM来说,它们是两个不同的实例对象

  11. 但它们确实是同一份字节码文件如果试图将这个Class实例生成具体的对象进行转换时

  12. 就会抛运行时异常java.lang.ClassCaseException,提示这是两个不同的类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值