龙都娱乐»Java WEB»你不知道Java的10件事

你不知道Java的10件事

来源:mydream20130314 发布时间:2014-11-21 阅读次数:
  你从一开始就在使用Java吗?你是否还记得java被称作为”Oak”的时期?那时,面向对象仍然是一个热门的话题,使用C++的人们都认为Java没有任何机会,Applets 也只是一件事情。   我敢打赌你肯定不知道以下一半的事情。现在,让我们开始一些Java内部运作的大惊喜。

  1. 并没有所谓的检查异常

  没错,Java虚拟机(JVM)不知道异常,只有Java语言自己知道.   如今,每个人都同意检查异常是一个错误。正如Bruce Eckel 在Prague的 GeeCON 闭幕词上所说,在Java之后没有其他语言会约定使用检查异常,甚至 Java 8  新的流API都不再包含这些(在lambdas表达式中使用IO 或者JDBC时,是有点痛苦)。   (译者注:Java8 引入了lambads表达式,使用它能够使设计代码更简洁)   使用下面的代码可以证明JVM并不知道这些:   上面的代码不仅能通过编译,而且抛出了异常SQLException,你甚至不需要使用Lombok’s 的注解@SneakyThrows。   (译者注:Lombok是一个使用注解简化Java代码的库)   (译者注:如果你在方法中没有声明throws子句,当程序出现异常时Lomok 注解@SneakyThrows 会偷偷的抛出检查异常)点这里获取关于这篇文章的更多细节,或 Stack Overflow。

  2. 重载仅返回类型不同的方法

  这不能通过编译,不是吗?   是的。Java语言不允许在同一个类中存在"等价覆盖" 的两个方法.不管它们有不同的 throws 子句或是不同的返回类型。   在 Javadoc  Class.getMethod(String,Class...)。上面有如下说明:   注意:它在一个类中可能会匹配到多个方法,虽然Java语言禁止在一个类中声明多个签名相同而仅返回类型不同的方法,但是Java虚拟机不会如此。在Java虚拟机中,这种增强 的灵活性被用于实现多样的语言特性。例如,协变返回值类型能通过桥接方法实现;桥接方法和被覆盖的方法将有相同的签名,不同的返回类型。   这很有意义,事实上,下面的语句所发生的几乎就是这样。   查看生成的字节码:   因此,很好理解 T 在字节码中就是一个对象。   这个合成的桥接方法实际上是由编译器生成的,因为Parent.x()的返回类型签名在某些调用位置可能会被期望成 Object。   加入的泛型没有这样的桥接方法就不可能以一种二进制的方式兼容。   因此,改变JVM去支持这种特性只需很少的代价(同样也允许协变性压倒一切负效应)很聪明,不是吗?   你分析过语言的细节和内幕吗?点这里发现更多有趣的细节。

  3. 这些都是二维数组

  这是真的。你可能无法立刻理解上面方法的返回类型,但它们都是一样的。类似于下面的方法:   你肯定认为这疯了。想象一下,为上面的方法使用 JSR-308 / Java 8 的类型注解。句法的数量将会激增。

  4. 你不明白条件表达式

  你认为你在使用条件表达式时明白一切吗?让我告诉你吧,你不明白。大多数人都会认为下面两个代码片段是等价的:   真的一样吗?   不一样。我们来验证一下:   程序的输出结果为: 1.0 1   没错!条件运算符在必要的时候将实现数据类型的提升。下面的语句将会抛出一个NullPointException。   点这里获取更多细节。

  5. 你也不明白复合赋值运算符

  看下面的代码:   乍一看它们应该是等价的,但事实上不是。见 JSL(Java语言规范):   复合赋值表达式 E1 op= E2 与 E1 = (T)((E1) op (E2)) 是等价的,T的类型与E1相同,此外 E1仅计算一次。   这真是太美了,我想引用Peter Lawrey's 关于堆栈溢出问题的回答:

  6. 随机整数

  这是一个难题。不要参看解答,你能独立的解决问题吗?   运行下面的代码:   我有时候会得到如下输出: 92 221 45 48 236 183 39 193 33 84   这怎么可能?   答案在这。通过反射覆盖 JDK's 的 Integercache,然后使用自动装箱和自动拆箱机制。   运行上面的代码,你就可以得到类似的结果了。

  7. GOTO

  在Java中编写下列语句:   程序会编译失败,错误信息为:   因为goto是一个未使用的关键字。   虽然无法在源码中直接使用 goto 但是我们可以通过 break,continue 和 标记块实现。   字节码的 goto;   向前跳转:   它的字节码为:   向后跳转:   它的字节码为:   看,是不是出现了goto

  8. Java 的类型别名

  在其他语言中可以很简单的使用类型别名,例如Ceylon:   (译者注:Ceylon是一种新兴的计算机龙都娱乐,号称"Java杀手",它不是Java,而是一种受Java影响的新语言。)   以这种方式构造的 People 可以被 Set<Person> 替换:   在Java中,我们无法在全局范围上定义类型别名。由于存在 class 域或方法域,   亦可以定义。考虑两个我们很不喜欢的命名 Integer 和 Long,为它们取个简短的名称 I 和 L:   上面的程序中,在 TestClass 域内 定义 Integer 别名为 I,在 x() 方法域中定义Long   别名为 L。我们可以这样使用上面的方法:   显然这种技术不值得重视。在这个例子中,Integer 和 Long 都是 final 类型,也就意味着类型 I 和 L 是有效的别名(那样的话,程序与类型兼容性也就无缘了)。如果我们使用的不是 final 类型,那么就应该使用泛型。   看够了这些无聊的把戏了吧!来点厉害的。

  9. 一些不可判定的关系类型

  让我们来点咖啡,集中你的注意力,这可是很时髦的东西。考虑下面两个类型:   现在,你知道 C 和 D 的类型吗?   它们包含了递归,Java、lang、Enum 也是递归的。这两种方式有些相似,但略有不同。   由上面的规范可知,Enum 实际上是由一种糖衣语法实现的。   (译者注:糖衣语法,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用)   考虑到这一点,让我们回到先前定义的两个类型。下列代码能编译成功吗?   很难回答,Ross Tate 有个答案,不可判定:   尝试在你的Eclipse中编译上面的代码,崩溃了吧!   看这句话:   有些类型关系在Java中是不可判定的。   如果你有兴趣了解这个奇怪的Java特性更多细节,就读一读 Ross Tate的论文"Taming Wildcards in Java's Type System"(与 Alan Leung 和 Sorin Lerner 合著),或者自己思考关联子类型多态性与泛型多态性。

  10. 交集类型

  Java有一个很独特的特性称作交集类型(type intersections)。你可以声明一个泛型,它由两个类型的交集构成。例如:   要使用绑定的泛型参数 T 去实例化Test 类,这个参数就必须同时实现 Serializable 和 Cloneable。例如 String 不是,而 Date 是:   为了让你有一个专门的交集类型,这种特性在Java8中得到了重用。如何用它呢?几乎没用。但是,当你在 lambda 表达式中强行应用这样的类型时,就只有此种方法可行。   假设你在方法中使用了这种疯狂的类型约束:   你需要一个实现了Runnable 和Serializable 的对象。为了让你可以在某些地方执行它,或是发送它,   Lambads 可以被序列化:   如果一个lambda 表达式的目标类型和所需参数是可序列化的,那么这个表达式就能序列化。   即使这是真的,那也不会自动的实现序列化标记接口,所以你必须自己动手。   现在你有一个可序列化的,但是它不能被执行。   所以你必须自己加上:   英文:DZone,译者:黑葱
QQ群:WEB龙都娱乐官方群(515171538),验证消息:10000
微信群:加小编微信 849023636 邀请您加入,验证消息:10000
提示:更多精彩内容关注微信公众号:全栈龙都娱乐中心(fsder-com)
网友评论(共1条评论) 正在载入评论......
理智评论文明上网,拒绝恶意谩骂 发表评论 / 共1条评论
登录会员中心
龙都娱乐