java事件和事物的异同_关于 Java 你不知道的 10 件事

原标题:关于 Java 你不知道的 10 件事

来自:开源中国 协作翻译

链接:http://www.oschina.net/translate/10-things-you-didnt-know-about-java

原文:10 Things You Didn’t Know About Java

原文:https://www.sitepoint.com/10-things-you-didnt-know-about-java/

译者:边城, Tocy, 无若, 总长, AzureSora

作为 Java 书呆子,比起实用技能,我们会对介绍 Java 和 JVM 的概念细节更感兴趣。因此我想推荐 Lukas Eder 在 jooq.org 发表的原创作品给大家。

你是从很早开始就一直使用 Java 吗?那你还记得它的过去吗?那时,Java 还叫 Oak,OO 还是一个热门话题,C++ 的 folk 者认为 Java 是不可能火起来,Java 开发的小应用程序 Applets 还受到关注。

我敢打赌,下面我要介绍的这些事,有一半你都不知道。下面让我们来深入探索 Java 的神秘之处。

没有检查异常这种事情

没错!JVM 不会知道这些事情,只有 Java 语句知道。

如今大家都认为检查异常是个错误。正如 Bruce Eckel 在布拉格 GeeCON 闭幕时所说,Java 之后再没别的语言检查异常,甚至 Java 8 在新的 Stream API 中也不再干这个事情(如果你的 Lambda 使用 IO 和 JDBC,这其实还是有点痛苦)。

如何证实 JVM 并不清楚检查异常一事?试试下面的代码:

594cbbd5618041a373c1b2239e906388.png

这不仅可以编译通过,它还可以抛出 SQLException。你甚至不需要 Lombok 的 @SneakyThrows 就能办到。

这篇文章可以看到更详细的相关内容,或者在 Stack Overflow 上看。

你可以定义仅在返回值有差异的重载函数

这样的代码无法编译,对不?

094d156b81ae979aa7e7745491a90a72.png

对。 Java 语言不允许两个方法在同一个类中“等效重载”,而忽略其诸如throws自居或返回类型等的潜在的差异。

查看 Class.getMethod(String, Class...) 的 Javadoc。 其中说明如下:

请注意,类中可能有多个匹配方法,因为 Java 语言禁止在一个类声明具有相同签名但返回类型不同的多个方法,但 Java 虚拟机并不是如此。

虚拟机中增加的灵活性可以用于实现各种语言特征。例如,可以用桥接方法实现协变参返回; 桥接方法和被重写的方法将具有相同的签名但拥有不同的返回类型。

恩,有道理。实际上下面的代码暗藏着很多事情:

5f1e0c6c0adfdee538dcf2007e46e2be.png

来看看为 Child 生成的字节码:

303558a6604d04a8c9533a5611086c97.png

其实在字节码中 T 真的只是 Object。这很好理解。

合成的桥方法实际是由编译器生成的,因为 Parent.x() 签名中的返回类型在实际调用的时候正好是 Object。在没有这种桥方法的情况下引入泛型将无法在二进制下兼容。

因此,改变 JVM 来允许这个特性所带来的痛苦会更小(副作用是允许协变凌驾于一切之上) 很聪明,不是吗?

你看过语言内部的细节吗?不妨看看,在这里会发现更多很有意思的东西:

http://stackoverflow.com/q/442026/521799

所有这些都是二维数组!

5c25f3debd196eaddc6c773652e0214e.png

是的,这是真的。即使你的大脑解析器不能立刻理解上面方法的返回类型,但其实他们都是一样的!类似的还有下面这些代码片段:

1f488ba99edfabb6c9fca2e2a43abb3b.png

你认为这很疯狂?想象在上面使用 JSR-308 / Java 8 类型注解 。语法的可能性指数激增!

3c16dfd50e952b610ffc295151a1a657.png

类型注解。看起来很神秘,其实并不难理解。

或者换句话说:

当我做最近一次提交的时候是在我4周的假期之前。

d7de78ab1d943c2d052e06b7153afa22.png

对你来说,上面的内容在你的实际使用中找到了吧。

条件表达式的特殊情况

可能大多数人会认为:

是否等价于:

6c8dacc62173bc0dc800382d3e09dcdd.png

然而,事实并非如此。我们来测试一下就知道了。

42cecd71f362301d7ede028e4b454451.png

输出结果:

0b2661c821edbd9a6a18b9d569ba1174.png

由此可见,三目条件运算符会在有需要的情况下,对操作数进行类型提升。注意,是只在有需要时才进行;否则,代码可能会抛出 NullPointerException 空引用异常:

c9e1cde866ff6dcf9e41f3bc0fee1ac9.png

你还没搞懂复合赋值运算符

很奇怪吗?来看看下面这两行代码:

df4b6f074cdb1475f16150a05c2b0cd9.png

直观看来它们等价,是吗?但可其实它们并不等价!JLS 解释如下:

E1 op= E2 形式的复合赋值表达式等价于 E1 = (T)((E1) op (E2)),这里 T 是 E1 的类型,E1 只计算一次。

非常好,我想引用 Peter Lawrey Stack Overflow 上的对这个问题的回答

(http://stackoverflow.com/a/8710747/521799):

使用 *= 或 /= 来进行计算的例子

75bdc873604e54a528df8fc17b183d3d.png

或者

74d4d5984aac2ab1fa82709b8d3161c6.png

或者

ec470c572c9eb1a4c8487202aa0edb66.png

或者

387c58826344b221924b7218d5884904.png

现在看到它的作用了吗?我会在应用程序中对字符串进行乘法计算。因为,你懂的...

随机整数

现在有一个更难的谜题。不要去看答案,看看你能不能自己找到答案。如果运行下面的程序:

aa525f1ddfa9f590d6e44b6a63e7170b.png

… “有时候”,我会得到下面的输出:

7a51ca19392fc41f5b2ca69481d562e5.png

这怎么可能??

. spoiler… 继续解答…

好了,答案在这里

(https://blog.jooq.org/2013/10/17/add-some-entropy-to-your-jvm/),这必须通过反射重写 JDK 的 Integer 缓存,然后使用自动装箱和拆箱。不要在家干这种事情!或者,我们应该换种方式进行此类操作。

我在4周前做最后一次提交的时候

deee3166fdd5e18bb34af13d18a4eee3.png

GOTO

这是我的最爱之一。Java也有GOTO!输入下试试……

将输出:

35eceeee27f0904b5dd690c10b6303f7.png

这是因为goto是一个未使用的关键字, 仅仅是为了以防万一……

但这不是最令人兴奋的部分。令人兴奋的部分是你可以使用 break、continue 和标记块来实现 goto 功能:

向前跳:

c715634cfa768736e53d56db465cdc0c.png

在字节码中格式如下:

24bec3a790c670d6808cbab92b64027f.png

向后跳:

544fccc8925a3756eb156bfea2d55a6f.png

在字节码中格式如下:

e5cf79c8610da7c347959992eb5d08a6.png

Java 有类型别名

其它语言 (比如 Ceylon) 中,我们很容易为类型定义别名:

这里产生了 People 类型,使用它就跟使用 Set 一样:

d2410eea1e707b0ed89a48171ebea43d.png

Java 中我们不能在顶层作用域定义类型别名,但是我们可以在类或方法作用域中干这个事情。假如我们不喜欢 Integer、Long 等等名称,而是想用更简短的 I 和 L,很简单:

0b7f7e1d363130448a43351e90c4ea3a.png

在上面的程序中,Test 类作用域内 Integer 被赋予 I 这样的 “别名”,类似地,Long 在 x() 方法中被赋予 L 这样的 “别名”。之后我们可以这样调用方法:

这种技术当然不太会受重视。这种情况下,Integer 和 Long 都是 final 类型,也就是说,I 和 L 是事实上的别名(基本上赋值兼容性只需要考虑一种可能性)。

如果我们使用非 final 类型 (比如 Object),那就是一般的泛型。

这些把戏已经玩够了。现在来看看真正了不起的东西!

某些类型的关系并不确定!

好了,这会很引人注目,先来杯咖啡提提神。思考一下下面两个类型:

1ed43b57c7b65218784ad7b3aacc8d20.png

现在告诉我,类型 C 和 D 到底是什么?

它们存在递归,是一种类似 java.lang.Enum (但有略微不同)的递归方式。看看:

在上面的描述中,enum 实际上只是单纯的语法糖:

86ad902a47af425f9e952b79db5a1c74.png

认识到这一点之后我们回过头来看看前面提到的两个类型,下面的代码会编译成什么样?

a9d887a3ece023eff84212c2731d6f5a.png

非常难回答的问题,不过 Ross Tate 已经回答了。这个问题的答案是不可判定的:

C 是 Type super C> 的子类?

c74663c0e78446f342c9ff7b0cc94f80.png

然后:

D 是 Type super D> 的子类?

d71525bcd643cdae77a99ab17c564f8f.png

在 Eclipse 中试着编译一下,它会崩溃! (不用担心,我提交了 BUG 报告:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=449554)

让这个事情沉下去…

Java 中某些类型的关系是不明确的!

如果你对 Java 这个用法感到奇怪之余也感兴趣,就去看看 Ross Tate 写的 “在 Java 的类型系统中使用通配符” (与 Alan Leung 和 Sorin Lerner 合著):

http://www.cs.cornell.edu/~ross/publications/tamewild/tamewild-tate-pldi11.pdf

我们也在讨论泛型多态中的相关子类多态性:

https://blog.jooq.org/2013/06/28/the-dangers-of-correlating-subtype-polymorphism-with-generic-polymorphism/

类型交集

Java 有一个非常奇怪的特性叫类型交集。你可以申明某个(泛型)类型,而它实际上是两个类型的交集,比如:

3da735012594ef6ed1d72d45f55bfe17.png

绑定到 Test 类型实例的泛型类型参数 T 必须实现 Serializable 和 Cloneable。比如,String 就不符合要求,但 Dete 满足:

eea60f5084db8fcb396540f7888ca344.png

这个特性已经在 Java 8 中使用。这很有用吗?几乎没用,但是如果你希望某个 Lambda 表达式是这种类型,还真没别的办法。假设你的方法有这种疯狂的类型约束:

你想通过执行它得到一个可以序列化 (Serializable) 的 Runnable 对象。Lambda 和序列化也有点奇怪。

Lambda 可以序列化:

如果 Lambda 的目标类型和参数类型都可以序列化,那么你可以序列化这个 Lambda

但是即使是这样,他们都不能自动实现 Serializable 标记接口。你必须强制转换类型。但是当你只扔给 Serializable 时...

... 那么 lambda 将不再是 Runnable 的。

因此要把它转换为两种类型:

结论

一句话总结这篇文章就是:

Java 恰好是一种看起来神秘的语言,其实不然。

●本文编号531,以后想阅读这篇文章直接输入531即可

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器打开此项目。然后有一个 index.html 文可供您修改。在命令提示符运行该文,或者您可以直接运行索引文。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值