前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于 Java 你不知道的十件事

关于 Java 你不知道的十件事

作者头像
哲洛不闹
发布2018-09-14 11:18:20
6010
发布2018-09-14 11:18:20
举报
文章被收录于专栏:java一日一条java一日一条

作为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 不知道异常检查这件事吗?尝试以下代码:

这个不仅会编译,还会抛出 SQLException ,你甚至不需要 Lombok 的 @SneakyThrows 标签。

更多详情请参考这篇文章,或者 Stack Overflow 上的这篇文章。

2. 可以使用不同的返回值类型来重载方法

以下代码是编译不过的,对吧?

是的,Java 不允许在一个类中通过不同的返回值类型和异常语句来重载方法。

不过稍等,Java 文档中关于 Class.getMethod(String, Class…) 这样写道:

请注意,在一个类中会有多个匹配的方法,因为虽然 Java 语法规则禁止一个类中存在多个方法函数签名相同仅仅返回类型不同,但 JVM 允许。这样提高了 JVM 的灵活性以实现各种语言特性。例如,可以用桥接方法(bridge method)来实现方法的协变返回类型,桥接方法和被重载的方法可以有相同的函数签名和不同的返回值类型。

喔,这是合理的。事实上,以下代码就是这样执行的,

Child 类编译后的字节码是这样的:

看,T 在字节码中就是 Object,这个很好理解。

合成桥接方法是编译器自动生成的,因为 Parent.x() 签名的返回值类型被认为是 Object。如果没有这样的桥接方法是无法在兼容二进制的前提下支持泛型的。因此,修改 JVM 是实现这个特性最简单的方法了(同时实现了协变式覆盖)。很聪明吧。

你明白语言的内部特性了吗? 这里有更多细节。

3. 这些都是二维数组

是的,这是真的。即使你人肉编译以上代码也无法立刻理解这些方法的返回值类型,但他们都是一样的,与以下代码类似:

你认为很疯狂是不是?如果使用 JSR-308 / Java 8 类型注解的话,语句的数量会爆炸性增长的!

类型注解,它的诡异性只是被他强大的功能掩盖了。

换句话说:

当我在4周假期之前的最后一次代码提交中这么做的话

为以上所有内容找到相应的实际用例的任务就交给你啦。

4. 你不懂条件表达式

你以为你已经很了解条件表达式了吗?我告诉你,不是的。大多数人会认为以下的两个代码片段是等效的:

与下边的等效吗?

答案是并非如此,我们做个小测试。

是的,在确有必要的情况下,条件表达式会升级数字类型。你希望这个程序抛出一个空指针异常吗?

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

很诡异吗?让我们来看以下两段代码:

直觉上,他们是等价的吧?事实上不是,Java 语言规范(Java Language Standard,JLS)中这样写道:

符合赋值表达式 E1 op= E2 E1 = (T)((E1) op (E2)) 是等价的,这里 T E1 的类型,期望 E1 只被求值一次。

很美吧,我想引用 Peter Lawrey 在 Stack Overflow 上回复,

这种类型转换很好的一个例子是使用 *= or /=

这个很有用吧?我会将它们应用到我的程序里。原因你懂的。

6. 随机数

这更像是一道题,先别看结果。看你自己能否找到答案。当我运行以下程序时,

这是怎么回事?

答案已经在前面剧透了……

答案在这里( https://blog.jooq.org/2013/10/17/add-some-entropy-to-your-jvm/ ),需要通过反射来重载 JDK 中的 Integer 缓存,然后使用自动装箱(auto-boxing)和自动拆箱(auto-unboxing)。千万不要这么做,我们假设如果再做一次

我在4周假期之前的最后一次代码提交中这么做了

7. GOTO

这是我喜欢的一个。Java 有 GOTO 语句!输入以下:

但这不是最激动人心的部分。最给力的是你可以通过 break、continue 以及标签代码块来实现 goto。

向前跳转

8. Java 支持类型别名(type aliases)

在其它语言中(例如:Ceylon),定义类型别名是很容易的。

这个技术别太当真。在上边的例子里,Integer 和 Long 都是 final 类型, 也就是说 I 和 L 效果上是类型别名(大多数情况下,赋值兼容是单向的)。如果我们用非 final 的类型(例如 Object),就需要使用原来的泛型了。

以上是一些雕虫小技,下面才是真正有用的!

9. 一些类型之间的关系是不确定的!

这个会很有趣的,所以来一杯咖啡然后集中注意力。假设以下两种类型:

这是个很难的问题,Ross Tate 已经回答了。答案是不确定的:

C 是 <? super C> 的子类型吗?

尝试在 Eclipse 中编译以上代码,Eclipse 会挂掉的!(不要担心,我已经提过 bug 了)

理解下这个…

Java 中的一些类型的关系是不确定的!

如果你想了解更多关于 Java 的这个特性,请阅读 Ross Tate 与 Alan Leung 和 Sorin Lerner 共同编著的论文 “Taming Wildcards in Java’s Type System”或者我们自己总结的 correlating subtype polymorphism with generic polymorphism。

10. 类型交集(Type intersections)

Java 有个特性叫做类型交集。你可以声明一个泛型,这个泛型是两个类型的交集,例如:

Java 8 中保留了这个功能,你可以将类型转换为临时的类型交集。这有用吗?几乎没用,但如果你想要将lambda表达式强制转换为这个类型,除此就别无他法了。我们假设你的方法有这个疯狂的类型限制:

你想要同时支持 Runnable 和 Serializable,是为了以防万一要在网络的另一处执行它。Lambda 和序列化都有些古怪:

Lambda 表达式可以被序列化:

如果一个 lambda 表达式的返回值和输入参数可以被序列化,则这个表达式是可以被序列化的。

但即使这是真的,它也不会自动继承 Serializable 接口。你需要转换才能成为那个类型。但如果你只是转换为 Serializable…

lambda 就不支持 Runnable 了。

所以,

把它转换为两个类型:

结论

我经常只这么说 SQL,但现在要用下边的话来总结这篇文章了:

Java 语言的诡异性只是被它解决问题的能力掩盖了。

这是一个来自每日分享架构和项目管理的程序员的公众号,走心的文字,用心精选的每个技术以及业内文章。

每日励志名言,和你们一起成长,每天精选优质文章,每天推出一篇结构或技术好文,采用代码+文章+git源码。

让你在巨人的肩膀成长,不定期邀请高级程序员或架构师发推,我们一起成长。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java一日一条 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 受检异常(checked exception)这件事是不存在的
  • 2. 可以使用不同的返回值类型来重载方法
  • 3. 这些都是二维数组
  • 4. 你不懂条件表达式
  • 5. 你也不懂复合赋值运算符
  • 6. 随机数
  • 7. GOTO
  • 8. Java 支持类型别名(type aliases)
  • 9. 一些类型之间的关系是不确定的!
  • 10. 类型交集(Type intersections)
  • 结论
相关产品与服务
项目管理
CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档