作为Java 控,我们老是对不太大概直接利用,但能使我们更相识 Java 和 Java 虚拟机(Java Virtual Machine,JVM) 的艰涩细节感乐趣。这也是我将 Lukas Eder 在 jooq.org 上写的这篇文章宣布出来的原因。
你在Java宣布的时候就开始利用了吗?还记得当时它叫“Oak”,面向工具也 (Object Oriented, OO )照旧个热门话题,C++ 措施员们以为 Java 完全没时机乐成,Applet的呈现也是一件新鲜大事?
我赌博下文中至少一半的内容你都不知道。让我们来看看这些令人惊喜的 Java 细节吧。
1. 受检异常(checked exception)这件事是不存在的
是这样的,JVM 完全不知道这件事,都是Java语言做的[只有Java语言这么干]。
此刻,异常查抄被公认为是个错误,正如 Brue Eckel 在布拉格的 GeeCON 大会上的闭幕词中所说, Java 后的其他语言都不再利用异常查抄了,就连 Java 8 都不肯在新的 Stream API 中利用它了(当你在 lambda 表达式中利用 IO 可能 JDBC 时,是很疾苦的)。
你想要证明 JVM 不知道异常查抄这件事吗?实验以下代码:
java; gutter: true">public class Test { // No throws clause here public static void main(String[] args) { doThrow(new SQLException()); } static void doThrow(Exception e) { Test.<RuntimeException> doThrow0(e); } @SuppressWarnings("unchecked") static <E extends Exception> void doThrow0(Exception e) throws E { throw (E) e; } }
这个不只会编译,还会抛出 SQLException ,你甚至不需要 Lombok 的 @SneakyThrows 标签。
更多详情请参考这篇文章,可能 Stack Overflow 上的这篇文章。
2. 可以利用差异的返回值范例来重载要领
以下代码是编译不外的,对吧?
java; gutter: true">class Test { Object x() { return "abc"; } String x() { return "123"; } }
是的,Java 不答允在一个类中通过差异的返回值范例和异常语句来重载要领。
不外稍等,Java 文档中关于 Class.getMethod(String, Class…) 这样写道:
请留意,在一个类中会有多个匹配的要领,因为固然 Java 语礼貌则克制一个类中存在多个要领函数签名沟通仅仅返回范例差异,但 JVM 答允。这样提高了 JVM 的机动性以实现各类语言特性。譬喻,可以用桥接要领(bridge method)来实现要领的协变返回范例,桥接要领和被重载的要领可以有沟通的函数签名和差异的返回值范例。
喔,这是公道的。事实上,以下代码就是这样执行的,
abstract class Parent<T> { abstract T x(); } class Child extends Parent<String> { @Override String x() { return "abc"; } }
Child 类编译后的字节码是这样的:
// Method descriptor #15 ()Ljava/lang/String; // Stack: 1, Locals: 1 java.lang.String x(); 0 ldc </String><String "abc"> [16] 2 areturn Line numbers: [pc: 0, line: 7] Local variable table: [pc: 0, pc: 3] local: this index: 0 type: Child // Method descriptor #18 ()Ljava/lang/Object; // Stack: 1, Locals: 1 bridge synthetic java.lang.Object x(); 0 aload_0 [this] 1 invokevirtual Child.x() : java.lang.String [19] 4 areturn Line numbers: [pc: 0, line: 1]
看,T 在字节码中就是 Object,这个很好领略。
合成桥接要领是编译器自动生成的,因为 Parent.x() 签名的返回值范例被认为是 Object。假如没有这样的桥接要领是无法在兼容二进制的前提下支持泛型的。因此,修改 JVM 是实现这个特性最简朴的要领了(同时实现了协变式包围)。很智慧吧。
你大白语言的内部特性了吗? 这里有更多细节。
3. 这些都是二维数组
class Test { int[][] a() { return new int[0][]; } int[] b() [] { return new int[0][]; } int c() [][] { return new int[0][]; } }
是的,这是真的。纵然你人肉编译以上代码也无法立即领略这些要领的返回值范例,但他们都是一样的,与以下代码雷同:
class Test { int[][] a = {{}}; int[] b[] = {{}}; int c[][] = {{}}; }
你认为很猖獗是不是?假如利用 JSR-308 / Java 8 范例注解的话,语句的数量会爆炸性增长的!
@Target(ElementType.TYPE_USE) @interface Crazyy {} class Test { @Crazyy int[][] a1 = {{}}; int @Crazyy [][] a2 = {{}}; int[] @Crazyy [] a3 = {{}}; @Crazyy int[] b1[] = {{}}; int @Crazyy [] b2[] = {{}}; int[] b3 @Crazyy [] = {{}}; @Crazyy int c1[][] = {{}}; int c2 @Crazyy [][] = {{}}; int c3[] @Crazyy [] = {{}}; }
范例注解,它的诡异性只是被他强大的成果掩盖了。
换句话说:
当我在4周假期之前的最后一次代码提交中这么做的话
为以上所有内容找到相应的实际用例的任务就交给你啦。
4. 你不懂条件表达式