关于Java的十件事

那么,您从一开始就一直在使用Java? 还记得曾经被称为“ Oak”的日子,OO仍然是热门话题,C ++人士认为Java没有机会,Applet还是一件事吗?

我敢打赌,您至少不了解以下一半内容。 让我们从本周开始,对Java的内部运作产生一些惊喜。

1.没有被检查的异常

那就对了! JVM不知道任何这样的事情,只有Java语言知道。

今天,每个人都同意检查异常是一个错误。 正如Bruce Eckel在布拉格GeeCON闭幕致辞中所说的那样,在Java参与使用受检查的异常之后,没有其他语言可以使用,甚至Java 8也不再将它们包含在新的Streams API中( 实际上可能有点麻烦,当您的lambda使用IO或JDBC时 )。

您是否想要证明JVM不知道这样的事情? 尝试以下代码:

public class Test {// No throws clause herepublic 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语言不允许在同一个类中将两种方法“替代等效” ,无论它们的throws子句或return类型可能如何不同。

但是请稍等。 Class.getMethod(String, Class...)Class.getMethod(String, Class...)的Javadoc。 内容为:

请注意,一个类中可能有多个匹配方法,因为Java语言禁止一个类声明具有相同签名但返回类型不同的多个方法,而Java虚拟机却没有。 虚拟机中这种增加的灵活性可用于实现各种语言功能。 例如,协变收益可以通过过渡方法来实现。 bridge方法和被重写的方法将具有相同的签名,但返回类型不同。

哇,是的,这很有意义。 实际上,这几乎就是您编写以下内容时发生的情况:

abstract class Parent<T> {abstract T x();
}class Child extends Parent<String> {@OverrideString x() { return "abc"; }
}

Child检查生成的字节码:

// Method descriptor #15 ()Ljava/lang/String;// Stack: 1, Locals: 1java.lang.String x();0  ldc <String "abc"> [16]2  areturnLine 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: 1bridge synthetic java.lang.Object x();0  aload_0 [this]1  invokevirtual Child.x() : java.lang.String [19]4  areturnLine numbers:[pc: 0, line: 1]

因此, T实际上只是字节码中的Object 。 很好理解。

合成桥方法实际上是由编译器生成的,因为在某些调用位置可能期望Parent.x()签名的返回类型为Object 。 如果没有这种桥接方法,则无法以二进制兼容的方式添加泛型。 因此,更改JVM以使其具有此功能的痛苦就较小(这也使协变量重载成为副作用……)聪明吧?

您是否熟悉语言细节和内部知识? 然后在这里找到一些更有趣的细节 。

3.所有这些都是二维数组!

class Test {int[][] a()  { return new int[0][]; }int[] b() [] { return new int[0][]; }int c() [][] { return new int[0][]; }
}

对,是真的。 即使您的心理分析器可能无法立即理解上述方法的返回类型,它们也是相同的! 与以下代码段相似:

class Test {int[][] a = {{}};int[] b[] = {{}};int c[][] = {{}};
}

你觉得这很疯狂吗? 想象一下在上面使用JSR-308 / Java 8类型注释 。 句法可能性的数量激增!

@Target(ElementType.TYPE_USE)
@interface Crazy {}class Test {@Crazy int[][]  a1 = {{}};int @Crazy [][] a2 = {{}};int[] @Crazy [] a3 = {{}};@Crazy int[] b1[]  = {{}};int @Crazy [] b2[] = {{}};int[] b3 @Crazy [] = {{}};@Crazy int c1[][]  = {{}};int c2 @Crazy [][] = {{}};int c3[] @Crazy [] = {{}};
}

输入注释。 仅凭其力量超越神秘感的设备

换句话说:

当我这样做时,我的四周假期前的最后一次提交

hexhyZ8

我将为您找到上述任何一个用例的实际练习。

4.您没有条件表达式

因此,您认为使用条件表达式时就知道这一切吗? 我告诉你,你没有。 你们大多数人都认为以下两个片段是等效的:

Object o1 = true ? new Integer(1) : new Double(2.0);

…一样吗?

Object o2;if (true)o2 = new Integer(1);
elseo2 = new Double(2.0);

不。 让我们进行快速测试

System.out.println(o1);
System.out.println(o2);

该程序将打印:

1.0
1

是的 有条件的运营商将实现数字式的推广,如果“被需要”,与认为“需要”一个非常非常非常强的引号。 因为,您希望该程序抛出NullPointerException吗?

Integer i = new Integer(1);
if (i.equals(1))i = null;
Double d = new Double(2.0);
Object o = true ? i : d; // NullPointerException!
System.out.println(o);
  • 有关上述内容的更多信息,请参见此处 。

5.您也没有得到复合赋值运算符

够古怪吗? 让我们考虑以下两段代码:

i += j;
i = i + j;

凭直觉,它们应该等效,对吗? 但猜猜怎么了。 他们不是! JLS指定:

形式为E1 op = E2的复合赋值表达式等效于E1 =(T)((E1)op(E2)),其中T是E1的类型,只是E1仅被评估一次。

这是如此美丽,我想引用Peter Lawrey 对这个Stack Overflow问题的回答 :

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

byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57

要么

byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40

要么

char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'

要么

char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'

现在,这有多大用处? 我将在我的应用程序中强制转换/乘法。 因为,你知道...

6.随机整数

现在,这更像是一个难题。 尚未阅读解决方案。 看看您是否可以自己找到这个。 当我运行以下程序时:

for (int i = 0; i < 10; i++) {System.out.println((Integer) i);
}

…然后“有时”,我得到以下输出:

92
221
45
48
236
183
39
193
33
84

这怎么可能呢??

。 扰流板...未来的解决方案...

好的,解决方案就在这里 ,它与通过反射覆盖JDK的Integer缓存有关,然后使用自动装箱和自动拆箱。 不要在家做! 换句话说,让我们再这样考虑一下

当我这样做时,我的四周假期前的最后一次提交

hexhyZ8(1)

7.转到

这是我的最爱之一。 Java有GOTO! 输入...

int goto = 1;

这将导致:

Test.java:44: error: <identifier> expectedint goto = 1;^

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

但这不是令人兴奋的部分。 令人兴奋的部分是,您实际上可以使用breakcontinue和带标签的块来实现goto:

向前跳

label: {// do stuffif (check) break label;// do more stuff
}

在字节码中:

2  iload_1 [check]
3  ifeq 6          // Jumping forward
6  ..

向后跳

label: do {// do stuffif (check) continue label;// do more stuffbreak label;
} while(true);

在字节码中:

2  iload_1 [check]3  ifeq 96  goto 2          // Jumping backward9  ..

8. Java具有类型别名

在其他语言中( 例如Ceylon ),我们可以非常轻松地定义类型别名:

interface People => Set<Person>;

这样构造的People类型可以与Set<Person>互换使用:

People?      p1 = null;
Set<Person>? p2 = p1;
People?      p3 = p2;

在Java中,我们不能在顶级定义类型别名。 但是我们可以在类或方法的范围内这样做。 让我们考虑一下,我们对IntegerLong等的命名感到不满意,我们希望使用较短的名称: IL 简单:

class Test<I extends Integer> {<L extends Long> void x(I i, L l) {System.out.println(i.intValue() + ", " + l.longValue());}
}

在上述程序中,对于Test类的范围, Integer被“别名”到I ,而对于x()方法的范围, Long被“别名”到L 然后我们可以像上面这样调用上面的方法:

new Test().x(1, 2L);

当然,这种技术不应被认真对待。 在这种情况下, IntegerLong都是最终类型,这意味着类型IL 实际上是别名(几乎,赋值兼容只是一种方式)。 如果我们使用了非最终类型(例如Object ),那么我们实际上将使用普通的泛型。

这些愚蠢的把戏足够了。 现在换个真正了不起的东西!

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

好吧,现在这将变得非常时髦,因此可以喝杯咖啡并集中精力。 请考虑以下两种类型:

// A helper type. You could also just use List
interface Type<T> {}class C implements Type<Type<? super C>> {}
class D<P> implements Type<Type<? super D<D<P>>>> {}

现在,类型CD甚至意味着什么?

它们有些递归,以类似于java.lang.Enum递归的方式(但略有不同)。 考虑:

public abstract class Enum<E extends Enum<E>> { ... }

使用以上规范,实际的enum实现仅仅是语法糖:

// This
enum MyEnum {}// Is really just sugar for this
class MyEnum extends Enum<MyEnum> { ... }

考虑到这一点,让我们回到两种类型。 以下内容可以编译吗?

class Test {Type<? super C> c = new C();Type<? super D<Byte>> d = new D<Byte>();
}

艰苦的问题, 罗斯·泰特 ( Ross Tate)有了答案。 这个问题实际上是无法确定的:

C是Type <的子类型吗? 超级C>?

Step 0) C <?: Type<? super C>
Step 1) Type<Type<? super C>> <?: Type (inheritance)
Step 2) C  (checking wildcard ? super C)
Step . . . (cycle forever)

然后:

D是Type <的子类型吗? 超级D <Byte >>?

Step 0) D<Byte> <?: Type<? super C<Byte>>
Step 1) Type<Type<? super D<D<Byte>>>> <?: Type<? super D<Byte>>
Step 2) D<Byte> <?: Type<? super D<D<Byte>>>
Step 3) List<List<? super C<C>>> <?: List<? super C<C>>
Step 4) D<D<Byte>> <?: Type<? super D<D<Byte>>>
Step . . . (expand forever)

尝试在Eclipse中编译以上内容,它将崩溃! ( 不用担心。我已经提交了一个错误 )

让它沉入……

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

如果您对有关此奇特的Java怪癖的更多细节感兴趣,请阅读Ross Tate的论文“在Java的类型系统中使用通配符” (与Alan Leung和Sorin Lerner合着),或者阅读我们自己的有关将子类型多态与泛型多态相关联的想法。

10.类型交点

Java具有一个非常独特的功能,称为类型交集。 您可以声明一个(通用)类型,它实际上是两种类型的交集。 例如:

class Test<T extends Serializable & Cloneable> {
}

泛型类型参数T ,你绑定的类的实例Test必须实现 SerializableCloneable 。 例如, String不是可能的绑定,但Date是:

// Doesn't compile
Test<String> s = null;// Compiles
Test<Date> d = null;

Java 8中已重用了此功能,您现在可以在其中将类型转换为临时类型的交集。 这有什么用? 几乎没有,但是如果您想将lambda表达式强制为这种类型,则别无选择。 假设您的方法受到这种疯狂的类型约束:

<T extends Runnable & Serializable> void execute(T t) {}

您想要一个可SerializableRunnable ,以防您想在其他地方执行它并通过电线发送它。 Lambda和序列化有点古怪。

Lambda可以序列化 :

如果lambda表达式的目标类型和捕获的参数可序列化,则可以对其进行序列化

但是,即使这是真的,他们也不会自动实现Serializable标记接口。 要强制他们使用这种类型,必须强制转换。 但是,当您仅转换为Serializable ...

execute((Serializable) (() -> {}));

…然后,lambda将不再可运行。

嗯...

所以…

将其强制转换为两种类型:

execute((Runnable & Serializable) (() -> {}));

结论

我通常只说这是关于SQL的问题,但现在该是结束这篇文章的时候了:

Java是仅凭其强大功能就无法解开谜底的设备。

翻译自: https://www.javacodegeeks.com/2014/11/10-things-you-didnt-know-about-java.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361688.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

注释,无处不在的注释

十年前的2004年 &#xff0c; Java 1.5开始提供注释。 很难想象没有此功能的代码。 实际上&#xff0c;首先引入了注释&#xff0c;以减轻开发人员编写繁琐的样板代码的痛苦&#xff0c;并使代码更具可读性。 考虑一下J2EE 1.4&#xff08;没有可用的注释&#xff09;和Java EE…

JZTK项目 驾照题库项目servlet层得到的json字符串在浏览器中 汉字部分出现问号?无法正常显示的解决方法

servlet层中的代码如下&#xff1a; package com.swift.jztk.servlet;import java.io.IOException;import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletReque…

【RTOS】基于V7开发板的uCOS-III,uCOS-II,RTX4,RTX5,FreeRTOS原版和带CMSIS-RTOS V2封装层版全部集齐...

RTOS模板制作好后&#xff0c;后面堆各种中间件就方便了。 1、基于V7开发板的最新版uCOS-II V2.92.16程序模板&#xff0c;含MDK和IAR&#xff0c;支持uC/Probehttps://www.cnblogs.com/armfly/p/11255981.html 2、基于V7开发板的最新版uCOS-III V3.07.03程序模板&#xff0c;含…

三极管开关电路设计(转)

三极管开关电路设计 三极管除了可以当做交流信号放大器之外&#xff0c;也可以做为开关之用。严格说起来&#xff0c;三极管与一般的机械接点式开关在动作上并不完全相同&#xff0c;但是它却具有一些机械式开关所没有的特点。图1所示&#xff0c;即为三极管电子开关的基本电路…

OpenShift上具有NetBeans的Java EE

今天是慕尼黑的NetBeans日 。 我很高兴提出一个关于将Red Hat产品与我著名的IDE集成的会议。 因此&#xff0c;我一直在谈论WildFly &#xff0c; EAP &#xff0c;Git和OpenShift Online&#xff0c;并展示了使用该工具集优化开发工作流程的所有不同方式。 大约有100位与会者…

tomcat.apache startup.bat闪退两种解决方法

tomcat bin文件夹中的startup.bat闪退原因及解决方法两种 方法一&#xff1a;在启动tomcat时闪退&#xff0c;重新检查java的jre运行环境。如果环境变量忘记配置一定会导致了tomcat的闪退。 追加 Apache的bin的环境变量也放到path中 注意检查一下看 JAVA_HOME是否写错&#xff…

产生的DLL (VS2005, MATLAB7.5, mwArray)

from: http://www.simwe.com/forum/thread-801187-1-1.html 程序中使用MATLAB编译产生的DLL &#xff08;VS2005, MATLAB7.5, mwArray&#xff09; 最近有几个帖子都在讨论有关在C程序中使用MATLAB编译产生的动态链接库DLL。本 来想用原来帖子中给出的m代码作为例子&#xff0c…

启动LINUX下的TFTP服务器

第一步: 我们要确认,LINUX下是不是安装了TFTP-SERVER. 在LINUX下输入: rpm -q tftp-server 如出现如下回复: tftp-server-0.39-2 则表示tftp-server已安装. 第二步: 修改TFTP启动脚本: 方法一: 需要修改ftptpd的启动脚本vi /etc/xinetd.d/tftp加上 disable no 此时即可启动tf…

简单代码生成器原理剖析(一)

上篇文章&#xff08;深入浅出三层架构&#xff09;分析了简单三层架构的实现。包括Model,DAL&#xff08;数据访问层&#xff09;,BLL&#xff08;业务逻辑层&#xff09;的实现。 实际开发中&#xff0c;由于重复代码的操作&#xff0c;会花费大量时间&#xff0c;如果以代码…

Qt学习之路(4):初探信号槽

看过了简单的Hello, world! 之后&#xff0c;下面来看看Qt最引以为豪的信号槽机制&#xff01;所谓信号槽&#xff0c;简单来说&#xff0c;就像是插销一样&#xff1a;一个插头和一个插座。怎么说呢&#xff1f;当某种事件发生之后&#xff0c;比如&#xff0c;点击了一下鼠标…

注解的力量 -----Spring 2.5 JPA hibernate 使用方法的点滴整理(六): 一些常用的数据库 注解...

一、 实体 Bean 每个持久化POJO类都是一个实体Bean, 通过在类的定义中使用 Entity 注解来进行声明。 声明实体Bean Entitypublic class Flight implements Serializable { Long id; Id public Long getId() { return id; } public void setId(Long id) { this.id id; }} E…

SWT鼠标单击实现

最近&#xff0c;我做了一些SWT定制小部件的开发&#xff0c;偶然发现了一个问题&#xff0c; 为什么没有默认的SWT鼠标单击侦听器&#xff1f; 由于这个主题有时会提出&#xff0c;所以我认为写一两句话来说明背后的理性基础以及如何实现鼠标单击通常不会受到伤害。 SWT鼠标请…

响应式布局笔记

一. 布局设计 固定布局&#xff1a;以像素作为页面的基本单位&#xff0c;不管设备屏幕及浏览器宽度&#xff0c;只设计一套尺寸&#xff1b; 可切换的固定布局&#xff1a;同样以像素作为页面单位&#xff0c;参考主流设备尺寸&#xff0c;设计几套不同宽度的布局。通过设别的…

麦冬

麦冬 中文学名&#xff1a;麦冬 拉丁学名&#xff1a;Ophiopogon japonicus (Linn. f.) Ker-Gawl. 别称&#xff1a;麦门冬、沿阶草 植物界百合科 主要价值&#xff1a; 1、有养阴润肺、益胃生津、清心除烦的功效&#xff0c;用于肺燥干咳、阴虚痨嗽、喉痹咽痛、津伤口渴、…

Java EE 7 / JAX-RS 2.0 – REST上的CORS

Java EE REST应用程序通常在开箱即用的开发机器上运行良好&#xff0c;该开发机器上所有服务器端资源和客户端UI均指向“ localhost”或127.0.0.1。 但是&#xff0c;当涉及跨域部署时&#xff08;当REST客户端不再与托管REST API的服务器位于同一域时&#xff09;&#xff0c;…

jQuery框架-1.jQuery基础知识

jQuery简介 jQuery&#xff0c;顾名思义是JavaScript和查询&#xff08;Query&#xff09;&#xff0c;jQuery是免费、开源的。它可以简化查询DOM对象、处理事件、制作动画、处理Ajax交互过程且兼容多浏览器的javascript库&#xff0c;核心理念是write less,do more(写得更少,…

用CornerStone配置SVN,HTTP及svn简单使用说明

原文地址&#xff1a;&#xff1a;&#xff1a;http://my.oschina.net/joanfen/blog/194491#OSC_h2_3 一、下载地址二、安装破解方法三、添加repository 1.SVN配置 2.HTTP配置四、使用简介 1.上传项目到repository 2.下载项目 3.版本管理 a)先更新后提交 b)完成独立功…

CentOS6.4 Install FTP

目录 安装参考传输模式遇到无法显示远程文件夹报错安装参考 https://www.cnblogs.com/walblog/articles/7890226.html 传输模式 主动模式被动模式遇到无法显示远程文件夹报错 点击属性设置&#xff1a; 搞定。 转载于:https://www.cnblogs.com/mysticbinary/articles/11271647.…

用于单元测试的JUnit教程–最终指南(PDF下载)

编者注&#xff1a; 我们在Java Code Geeks上提供了许多JUnit教程&#xff0c;例如JUnit入门示例 &#xff0c; 使用断言和注释的 JUnit 示例 &#xff0c; JUnit注释示例等。 但是&#xff0c;为了方便读者&#xff0c;我们希望将所有JUnit功能收集在一份详细的指南中。 我们…

EF 拉姆达 linq if else (整理)

首先想到&#xff1a;结果不正确&#xff01; var data0 db.T_Plants2; //这里加.AsQueryable()if (locationType 1){.Where(d > d.NaturalEcosystem true);}else{.Where(d > d.BuiltUpArea true);}.Select(d > new{AnimalID d.PlantID,Species d.Species,}).To…