呃,你是不是写了几年Java?这些我还依稀记得:那些年,它还叫橡树;那些年,面向对象仍然是一个热门话题;那些年,学C++的同学觉得Java没有前途;那些年,Applet还是风头正劲……但我敢打赌,这些东西你至少有一半还不知道。本周让我们来谈谈一些可能会让您感到惊讶的Java内部机制。1.其实没有检查异常(checkedexception)是的!JVM不知道这些事情,只有Java语言知道。今天,每个人都同意检查异常是一个设计错误,Java语言中的一个设计错误。正如puceEckel在布拉格GeeCON会议上的演讲总结中所说,Java之后没有其他语言对检查异常有任何参考,甚至Java8的新流API(StreamsAPI)也不再包含检查异常(以lambdas的形式)。有了IO和JDBC,这个API用起来还是有点痛苦。)想证明JVM忽略检查异常?试试下面的代码:publicclassTest{//methodnotdeclared)staticvoiddoThrow0(Exceptione)throwsE{throw(E)e;}}不仅可以编译通过,还可以抛出SQLException,甚至不需要使用Lombok的@SneakyThrows。有关更多详细信息,您可以查看这篇文章或StackOverflow上的这个问题。2.可以有只返回不同类型的重载方法。下面的代码不会编译,是吗?classTest{Objectx(){return"abc";}Stringx(){return"123";}}是的!Java语言不允许一个类中的两个方法“重载一致”,不管这两个方法的throws子句或返回类型是否真的不同。但是等一下!看一下Class.getMethod(String,Class...)方法的Javadoc:注意一个类中可能有多个匹配方法,因为虽然Java语言禁止一个类中有多个相同签名的方法,但只有返回类型不同,但JVM不禁止。这使得JVM可以更灵活地实现各种语言特性。例如,可以使用桥接方法(pidgemethod)来实现方法的协变返回类型;桥接方法和重载方法可以具有相同的方法签名,但返回类型不同。嗯,这是有道理的。事实上,在编写以下代码时发生了这种情况:abstractclassParent{abstractTx();}classChildextendsParent{@OverrideStringx(){return"abc";}}看看子类生成的字节码://Methoddescriptor#15()Ljava/lang/String;//Stack:1,Locals:1java.lang.Stringx();0ldc[16]2areturnLinenumbers:[pc:0,line:7]Localvariabletable:[pc:0,pc:3]local:thisindex:0type:Child//Methoddescriptor#18()Ljava/lang/Object;//Stack:1,Locals:1bridgesyntheticjava.lang.Objectx();0aload_0[this]1invokevirtualChild.x():java.lang.String[19]4areturnLinenumbers:[pc:0,line:1]在字节码中,T其实就是Object类型。这很容易理解。合成桥方法实际上是由编译器生成的,因为Parent.x()方法签名在某些调用场景中需要Object返回类型。添加泛型而不生成此桥接方法是不可能实现二进制兼容性的。因此,让JVM允许此功能愉快地解决了这个问题(实际上允许协变重载方法包含具有副作用的逻辑)。你聪明吗?呵呵~要不要深入语言规范和内核看看?更多有趣的细节可以在这里找到。3.这些写法都是二维数组!classTest{int[][]a(){returnnewint[0][];}int[]b()[]{returnnewint[0][];}intc()[][]{returnnewint[0][];}}是的,这是真的。虽然你的人肉解析器不能马上看懂上面方法的返回类型,但是都是一样的!下面的代码也类似:classTest{int[][]a={{}};int[]b[]={{}};intc[][]={{}};}你觉得这是不是2乙?想象一下在上面的代码中使用JSR-308/Java8类型注释。语法糖量要爆炸了!@Target(ElementType.TYPE_USE)@interfaceCrazy{}classTest{@Crazyint[][]a1={{}};int@Crazy[][]a2={{}};int[]@Crazy[]a3={{}};@Crazyint[]b1[]={{}};int@Crazy[]b2[]={{}};int[]b3@Crazy[]={{}};@Crazyintc1[][]={{}};intc2@Crazy[][]={{}};intc3[]@Crazy[]={{}};}类型注解。这种设计引入的古怪之处仅被其解决问题的能力所抵消。或者换句话说:在我4周假期之前的最后一次提交中,我编写了这样的代码,然后。..【译注:那么,亲爱的同事,你就有救了,哼哼哼,哦哈哈哈哈~】以上用法请找出合适的使用场景,或者留作练习。4.你没有条件表达式那么,你认为你知道什么时候使用条件表达式吗?让我们面对现实吧,你还不知道。大多数人会认为以下两个代码段是等价的:Objecto1=true?newInteger(1):newDouble(2.0);相当于:Objecto2;if(true)o2=newInteger(1);elseo2=newDouble(2.0);我让你失望了。让我们做一个简单的测试:System.out.println(o1);System.out.println(o2);打印出来的结果是:1.01!如果是“required”,条件运算符会做数值类型的类型提升,这个“required”有非常非常非常强的引号。因为,你觉得下面的程序会不会抛出NullPointerException?Integeri=newInteger(1);if(i.equals(1))i=null;Doubled=newDouble(2.0);Objecto=true?i:d;//NullPointerException!System.out.println(o);关于这个可以在此处找到有关其中一个的更多信息。