安卓面试必备的JVM虚拟机制详解,看完之后简历上多一个技能( 八 )


不过呢 , 字节码中仍然存在泛型参数的信息 , 如方法声明里的 T foo(T) , 以及方法签名 Signature 中的 "(TT;)TT" , 这些信息可以通过反射 Api getGenericXxx 拿到 。
除此之外 , 需要注意的是 , 泛型结合数组会有一些容易忽视的问题 。 数组是协变且具体化的 , 数组会在运行时才知道并检查它们的元素类型约束 , 可能出现编译时正常但运行时抛出 ArrayStoreException , 所以尽可能的使用列表 , 这就是 Effective Java 中推荐的列表优先于数组的建议 。 这在我们看集合源码时也能发现的到 , 比如 ArrayList , 它里面存数据是一个 Object[] , 而不是 E[] , 只不过在取的时候进行了强转 。 还有就是利用通配符来提升 API 的灵活性 , 简而言之即 PECS 原则 , 上取下存 。 典型的案例即 Collections.copy 方法了:
Collections.copy(List dest, List src);JVM 是如何实现异常的?在 Java 中 , 所有的异常都是 Throwable 类或其子类 , 它有两大子类 Error 和 Exception 。当程序触发 Error 时 , 它的执行状态已经无法恢复 , 需要终止线程或者终止虚拟机 , 常见的比如内存溢出、堆栈溢出等;Exception 又分为两类 , 一类是受检异常 , 比如 IOException , 一类是运行时异常 RuntimeException , 比如空指针、数组越界等 。
接下来我会从三个方面阐述这个问题 。
首先是 , 异常实例的构造十分昂贵 。 这是由于在构造异常实例时 , JVM 需要生成该异常的栈轨迹 , 该操作逐一访问当前线程的 Java 栈桢 , 并且记录下各种调试信息 , 包括栈桢所指向方法的名字、方法所在的类名以及方法在源代码中的位置等信息 。
其次是 , JVM 捕获异常需要异常表 。 每个方法都有一个异常表 , 异常表中的每一个条目都代表一个异常处理器 , 并且由 from、to、target 指针及其异常类型所构成 。 form-to 其实就是 try 块 , 而 target 就是 catch 的起始位置 。 当程序触发异常时 , JVM 会检测触发异常的字节码的索引值落到哪个异常表的 from-to 范围内 , 然后再判断异常类型是否匹配 , 匹配就开始执行 target 处字节码处理该异常 。
最后是 finally代码块的编译 。 我们知道 finally 代码块一定会运行的(除非虚拟机退出了) 。 那么它是如何实现的呢?其实是一个比较笨的办法 , 当前 JVM 的做法是 , 复制 finally 代码块的内容 , 分别放在所有可能的执行路径的出口中 。
JVM 是如何实现注解的?其实也没啥银弹 , 主要就是要知道注解信息是存放在哪的?在 Java 字节码中呢是通过 RuntimeInvisibleAnnotations 结构来存储的 , 它是一个 Annotations 数组 , 毕竟类、方法、属性是可以加多个注解的嘛 。 在数组中的每一个元素又是一个 ElementValuePair 数组 , 这个里面存储的就是注解的参数信息 。
运行时注解可以通过反射去拿这些信息 , 编译时注解可通过 APT 去拿 , 基本上就没啥东西了 。
Android及JVM学习资源其实客户端开发的知识点就那么多 , 面试问来问去还是那么点东西 。 所以面试没有其他的诀窍 , 只看你对这些知识点准备的充分程度 。 so , 出去面试时先看看自己复习到了哪个阶段就好 。
这里再分享一下我面试期间的复习路线:(以下体系的复习资料是我从各路大佬收集整理好的)
《Android开发七大模块核心知识笔记》
安卓面试必备的JVM虚拟机制详解,看完之后简历上多一个技能文章插图
安卓面试必备的JVM虚拟机制详解,看完之后简历上多一个技能文章插图
安卓面试必备的JVM虚拟机制详解,看完之后简历上多一个技能文章插图
《379页Android开发面试宝典》


推荐阅读