qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

Java不为人知的10个真相

你是不是一开始就用Java来编程的呢?还记得当年它还被称为"Oak",OO还是热门的话题,C++的用户觉得Java没有前景,applets还只是个小玩意,菊花也还是一种花的时候吗?
  我敢打赌下面至少有一半是你不清楚的。这周我们来看一下跟Java的内部实现相关的一些神奇的事情。
  1. 其实根本没有受检查异常这回事
  没错!JVM压根儿就不知道有这个东西,它只存在于Java语言里。
  如今大家都承认受检查异常就是个错误。正如Bruce Eckel最近在布拉格的的GeeCON会议上所说的,除了Java外没有别的语言会使用受检查异常这种东西,即使是Java 8的新的Streams API中也不再使用这一异常了(不然当你的lambda表达式中用到IO或者JDBC的话就得痛苦死了)。
  如何能证实JVM确实不知道这个异常?看下下面这段代码:
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. 不同的返回类型也可以进行方法重载
  这个应该是编译不了的吧?
  class Test {
  Object x() { return "abc"; }
  String x() { return "123"; }
  }
  是的。Java语言并不允许同一个类中出现两个重写等价("override-equivalent")的方法,不管它们的throws子句和返回类型是不是不同的。
  不过等等。看下Java文档中的 Class.getMethod(String, Class...)是怎么说的。里面写道:
  尽管Java语言不允许一个类中的多个相同签名的方法返回不同的类型,但是JVM并不禁止,所以一个类中可能会存在多个相同签名的方法。这添加了虚拟机的灵活性,可以用来实现许多语言特性。比如说,可以通过bridge方法来实现协变返回(covariant return,即虚方法可以返回子类而不一定得是基类),bridge方法和被重写的方法拥有相同的签名,但却返回不同的类型。
  哇,这倒有点意思。事实上,下面这段代码就会触发这种情况:
  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 "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而已。这理解起来就容易多了。
  synthetic bridge方法是由编译器生成的,因为在特定的调用点Parent.x()签名的返回类型应当是Object类型。如果使用了泛型却没有这个bridge方法的话,代码的二进制形式就无法兼容了。因此,修改JVM以支持这个特性貌似更容易一些(这顺便还实现了协变返回),看起来还挺不错 的吧?
  你有深入了解过Java语言的规范和内部实现吗?这里有许多很有意思的东西。

posted on 2014-12-05 12:16 顺其自然EVO 阅读(189) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
<2014年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜