|
|
|
@ -23,6 +23,7 @@ JVM 相关口水话 |
|
|
|
|
11. JVM 是如何实现反射的? |
|
|
|
|
12. JVM 是如何实现泛型的? |
|
|
|
|
13. JVM 是如何实现异常的? |
|
|
|
|
14. JVM 是如何实现注解的? |
|
|
|
|
|
|
|
|
|
#### 内存区域 |
|
|
|
|
|
|
|
|
@ -196,6 +197,8 @@ JVM 也提供了内联缓存来加快动态绑定,它能够缓存虚方法调 |
|
|
|
|
|
|
|
|
|
#### JVM 是如何实现泛型的? |
|
|
|
|
|
|
|
|
|
除了泛型擦除,我还真的没啥可讲的了,毕竟也就只有这点东西。 |
|
|
|
|
|
|
|
|
|
#### JVM 是如何实现异常的? |
|
|
|
|
|
|
|
|
|
在 Java 中,所有的异常都是 Throwable 类或其子类,它有两大子类 Error 和 Exception。 当程序触发 Error 时,它的执行状态已经无法恢复,需要终止线程或者终止虚拟机,常见的比如内存溢出、对栈溢出等;Exception 又分为两类,一类是受检异常,比如 IOException,一类是运行时异常 RuntimeException,比如空指针、数组越界等。 |
|
|
|
@ -206,4 +209,10 @@ JVM 也提供了内联缓存来加快动态绑定,它能够缓存虚方法调 |
|
|
|
|
|
|
|
|
|
其次是,JVM 捕获异常需要异常表。每个方法都有一个异常表,异常表中的每一个条目都代表一个异常处理器,并且由 from、to、target 指针及其异常类型所构成。form-to 其实就是 try 块,而 target 就是 catch 的起始位置。当程序触发异常时,JVM 会坚持触发异常的字节码的索引值落到哪个异常表的 from-to 范围内,然后再判断异常类型是否匹配,匹配就开始执行 target 处字节码处理该异常。 |
|
|
|
|
|
|
|
|
|
最后是 finally代码块的编译。我们知道 finally 代码块一定会运行的(除非虚拟机退出了)。那么它是如何实现的呢?其实是一个比较笨的办法,当前 JVM 的做法是,复制 finally 代码块的内容,分别放在所有可能的执行路径的出口中。 |
|
|
|
|
最后是 finally代码块的编译。我们知道 finally 代码块一定会运行的(除非虚拟机退出了)。那么它是如何实现的呢?其实是一个比较笨的办法,当前 JVM 的做法是,复制 finally 代码块的内容,分别放在所有可能的执行路径的出口中。 |
|
|
|
|
|
|
|
|
|
#### JVM 是如何实现注解的? |
|
|
|
|
|
|
|
|
|
其实也没啥银弹,主要就是要知道注解信息是存放在哪的?在 Java 字节码中呢是通过 RuntimeInvisibleAnnotations 结构来存储的,它是一个 Annotations 数组,毕竟类、方法、属性是可以加多个注解的嘛。在数组中的每一个元素又是一个 ElementValuePair 数组,这个里面存储的就是注解的参数信息。 |
|
|
|
|
|
|
|
|
|
运行时注解可以通过反射去拿这些信息,编译时注解可通过 APT 去拿,基本上就没啥东西了。 |