[JAVA 11] 17 个新特性
181: Nest-Based Access Control(基于嵌套的访问控制)
这个JEP最直接的表现就是修复了以下代码所表现出的问题:
/**
* JEP181 基于嵌套的访问控制
*/
public class JEP181 {
//定义 静态类 Inner2
public static class Inner2 {
//里面包含 私有变量 var2
private int var2;
}
//定义 静态类 Inner1
public static class Inner1 {
//共有方法 test
public void test() throws Exception {
// 创建 Inner2 对象
Inner2 var2 = new Inner2();
//对 var2 赋值 1
var2.var2 = 1;
//此处在没有JEP181的版本中执行会抛出错误
//使用反射 得到 Inner2的 Field
final Field f2 = Inner2.class.getDeclaredField("var2");
//设置 var2的 属性 为 2
f2.setInt(var2, 2);
}
}
public static void main(String[] args) throws Exception {
new Inner1().test();
}
}
作者:Leefish2016
链接:https://ld246.com/article/1540197841648
来源:链滴
协议:CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/
异常栈信息:
Exception in thread "main" java.lang.IllegalAccessException: Class JEP181$Inner1 can not access a member of class JEP181$Inner2 with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.setInt(Field.java:946)
at JEP181$Inner1.test(JEP181.java:18)
at JEP181.main(JEP181.java:30)
同时,查看内部类的字节码文件可以看到
左边的字节码的10行显示Inner2中存在一个access$002(Inner2, I)I的方法,这个方法正是对应了Inner1.test中的var2.var2 = 1;
而右边字节码的第10行,则表明Inner1是直接操作的Inner2中的var2字段。
根据官方文档,认为access$002这种方法,打破了封装。这个方法具体是:
通过直接在该类中对传入的该类的对象进行赋值。
309:Dynamic Class-File Constants(动态的类文件常量)
在Class-File中添加了一个新的常量池形式,称之为 CONSTANT_Dynamic
常量池标记为17(ASM框架中Symbol类可以查看到该值)
根据文档描述,
- invokedynamic 指令已经难以 完成当前对常量集编码的需要,
- 所以引入了CONSTANT_Dynamic,但目前为止该特性在ASM API中被注解为实验性接口。
* 由于目前该功能处于实验阶段,ASM并没有找到关于此功能实践代码,待补充
315:改进 Aarch64 Intrinsics(改进 Aarch64 Intrinsics)
简单来说,在AArch64 执行状态的CPU架构下,根据架构特性优化了多个JAVA方法。
例如java.util.Math下的
- sin (sine trigonometric function)
- cos (cosine trigonometric function)
- log (logarithm of a number)
提升了应用程序的基准测试性能。
ARMv8-AArch64简述
ARMv8是ARM版本升级以来最大的一次改变,ARMv8的架构继承以往ARMv7与之前处理器技术的基础,除了现有的16/32bit的Thumb2指令支持外,也向前兼容现有的A32(ARM 32bit)指令集,
扩充了基于64bit的AArch64架构,除了新增A64(ARM 64bit)指令集外,也扩充了现有的A32(ARM 32bit)和T32(Thumb2 32bit)指令集;
318:Epsilon 垃圾回收器,又被称为"No-Op(无操作)"回收器
-
这是一个实验性质的GC,简单来说,这个GC只会分配内存,而不会回收内存,
- 当堆内存耗尽时,JVM将直接关闭。
- 此GC因为不存在内存回收功能,所以编码者显式调用System.gc();是不会进行任何操作的。
-
使用方法: 启动JVM时追加参数 -XX:+UseEpsilonGC
这个GC主要的目标:
- 性能测试:将此GC作为其他GC对比的标准。
- 内存压力测试:由于该GC不存在内存回收,所以不用像以前一样通过分析日志来判断应用程序运行时内存是否已经超过指定大小,通过指定该GC的内存大小(with -Xmx1g),可以断定再不存在内存回收的情况下,应用程序是否满足该条件。
- 虚拟机接口测试,主要用于虚拟机的垃圾收集器接口。
- 执行短暂时间的任务:这类任务通常通过退出来快速释放堆内存,所以没有必要在内存分配回收上消耗时间。
- 最后的延迟改进:利用此GC的特性有可能打造出一个不产生内存垃圾的应用程序。
- 最后的优化吞吐量。
320:移除 Java EE 和 CORBA 模块
移除3个特性:
- JAVAEE:该技术栈用于java web开发,主要由四种技术组成:JAX-WS(基于XML的Web Service Api)、JAXB(用于XML和JAVA类的互相映射)、JAF(数据处理框架)、Common Annotations(通用注解,例如@Resource注解等),由于EE中出现了与SE开发无关的功能,且维护成本上升,在JAVA SE 9中被标记为弃用。
- CORBA:公共对象请求代理体系结构,一种规范。在JAVA中可以通过编写.idl实现这个功能。由于该模块的编写复杂性及在现代应用程序中开发使用率不高且维护成本远超带来的益处,在JAVA EE8中被列为“Proposed Optional”, 在JAVA SE 9被标记为弃用。
- JTA(javax.transcation):该包为CORBA提供服务。
此JEP删除模块列表:
- java.xml.ws(JAX-WS)
- java.xml.bind(JAXB)
- java.activation(JAF)
- java.xml.ws.annotation(Common Annotations)
- java.corba(CORBA)
- java.transaction(JTA)
- java.se.ee(上面六个模块的聚合,JAVA SE 9模块)
- jdk.xml.ws(JAX-WS工具)
- jdk.xml.bind(JAXB工具)
321:HTTP Client(Standard)
这是一个新的模块,包名称为java.net.http,而在jdk8中HttpClient位于sun.net.www.http.HttpClient;
此模块符合Http 2.0协议,且融入了 Reactive Flow的概念。
关于响应式编程可以百度Reactor 3的文章看看。
323:用于 Lambda 参数的局部变量语法
JDK10 中已经具有自动类型推断功能了,就像如下
var list = new ArrayList();
但在JDK10 运行一下代码会出现错误:
/**
* JEP323 用于 Lambda 参数的局部变量语法
* */
public class JEP323 {
public static void main( String[] args) {
Consumer<Integer> lambda = ( var a) -> {System.out.println(a);};
lambda.accept(3);
BinaryOperator<Integer> binaryOperator = (var a, var b) -> {return a + b;};
System.out.println(binaryOperator.apply(1, 2));
}
}
IDE会提示:var不该出现在此处。
但这段代码在JDK11的环境下能正常执行。
也就是以前的var只能用于局部变量和循环中,不能用于局部参数变量,此JEP已解决该问题。
但该局部参数变量var有个限制,不允许与隐式类型的参数混用,代码如下:
BinaryOperator<Integer> binaryOperator = (a, var b) -> {return a + b;};
System.out.println(binaryOperator.apply(1, 2));
lambda表达式中的(a, var b) a为隐式类型
//去掉 b 的 var,就可以了。
324:采用 Curve25519 和 Curve448 算法实现的密钥协议
-
Curve25519:是目前最高水平的 Diffie-Hellman函数,适用于广泛的场景,
-
由Daniel J. Bernstein教授设计。
-
由于NIST P-256的设计过程不透明,有来历不明的参数,被广泛怀疑有后门,
-
所以设计了Curve25519,Curve25519的设计过程完全公开,没有任何来历不明的参数。
RFC 7748:定义了一种密钥协商方案,该方案比现有的椭圆曲线Diffie-Hellman(ECDH)方案更有效和安全。
官方文档中示例API用法:
//KeyPair生成 为 XDH
KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");
//名称 参数 Spec 为 X25519
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
//初始化 KeyPair
kpg.initialize(paramSpec);
// equivalent to kpg.initialize(255)
// alternatively: kpg = KeyPairGenerator.getInstance("X25519")
//拿到 KeyPair
KeyPair kp = kpg.generateKeyPair();
//生成 KeyFactory 参数为 XDH
KeyFactory kf = KeyFactory.getInstance("XDH");
//定义 U
BigInteger u = BigInteger.TEN;
//定义 XECPublicKeySpec
XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);
//生成 publicKey
PublicKey pubKey = kf.generatePublic(pubSpec);
//得到 keyAgreement
KeyAgreement ka = KeyAgreement.getInstance("XDH");
//初始哈 ka
ka.init(kp.getPrivate());
//调用 doPhase
ka.doPhase(pubKey, true);
//得到秘钥
byte[] secret = ka.generateSecret();
语法中出现的 alternatively: 只是标记作用,示意阅读者可以选XDH和X25519
已定义的变量名前面加个 xxx: 对编译无影响,应该只是起说明作用, xxx不能使用关键字,且要符合JAVA变量命名的要求。
java15 的 Edwards-Curve 数字签名算法
EdDSA 具有更高的安全性和性能
//定义 byte []
byte[] msg="dddddddddddddd".getBytes();
// example: generate a key pair and sign 定义 KeyPairGenerator
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
//生成keyPair
KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519。 生成签名
Signature sig = Signature.getInstance("Ed25519");
//签名 初始化私钥
sig.initSign(kp.getPrivate());
//进行签名
sig.update(msg);
//得到 签名后的数据
byte[] s = sig.sign();
//使用 EdDSA ,获得 KeyFactory
// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
//定义 xOdd
boolean xOdd = true;
//定义一个 BigInteger
BigInteger y = BigInteger.ONE;
//名字 参数 说明
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
//new 一个公钥 Spec
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdECPoint(xOdd, y));
//用 KeyPair 得到 公钥
PublicKey pubKey = kf.generatePublic(pubSpec);
327:支持Unicode 10标准
支持Unicode 10标准,该标准具体内容可以查看Unicode 10
主要影响的类:
- java.lang.String
- java.lang.Character
- java.awt.font.NumericShaper
- java.text.Bidi;
- java.text.BreakIterator;
- java.text.Normalizer;
328:飞行记录仪(JFR)
此JEP提供了低开销的数据收集框架,用于对Java Application和HotSpot JVM进行故障排查。
JFR由以下部分组成:
- JFR运行时引擎:控制缓存、IO等、且提供了C和JAVA代码便携的动态连接库。
- JMC(Java Mission Control) 的FR插件,用于可视化界面。
使用该功能:
- 启动JVM时跟随参数:-XX:StartFlightRecording
- 也可以使用bin / jcmd工具启动:
jcmdJFR.start jcmd JFR.dump filename=recording.jfr
$ jcmd JFR.stop
官方也为用户提供了自定义JFR事件: jdk.jfr.*
329:实现 ChaCha20 和 Poly1305 加密算法
此JEP实现了两种加密算法,且大家担心的RC4安全问题也可以使用较新的ChaCha20来替代。
330:直接启动单个Java源文件
此JEP在java启动器原来的启动模式基础上(启动类文件、启动Jar文件的主类、启动模块的主类)增加了一种新的启动方式:源文件模式
源文件模式有两种启动方式:
源码:
public class Hello{
public static void main(String[] args){
System.out.println("abc");
}
}
- 如果以上代码被命名为Hello.java,则执行命令
java Hello.java
启动器会自动选择源文件模式。 - 如果该文件被命名为其他名字,例如Hello123,则必须带有–source参数:
java --source 11 Hello123
331:低开销的堆分配采样方法
略
332:支持TLS 1.3
略
333:ZGC:可伸缩的低延迟垃圾回收器
这是一个可扩展的低延迟GC。
特性:
- GC暂停时间不应该超过10ms。
- 处理的堆大小从百兆字节到兆兆字节
- 与使用G1的情况下,吞吐量减少不超过15%
目前只支持Linux/x64 平台。
335:弃用 Nashorn JavaScript 引擎
此引擎在JDK8中引入,因为ECMAScript语言快速迭代,Nashorn维护成本上升,目前已标记为弃用,会在后续版本删除该引擎,但官网也明确表明,此引擎如果有可靠的开发人员进行维护,则撤销该决定。
336:弃用 Pack200 工具及其 API
Pack200 是Jar文件的压缩方案,是在由JSR200在Java SE 5.0引入的,
- 而JDK8是该工具构建压缩时最后一个版本,从JDK9起已经不再依赖该工具。
删除原因:
- 由于当时的网络速率限制,需要Pack200来减少Jar文件的磁盘、带宽需求等。
- 而现在资源有所提高,JDK已经不需要Pack200了。
- 浏览器大多已不在运行Applet了
- 维护成本过高。
影响模块:
- java.util.jar.Pack200
- java.util.jar.Pack200.Packer
- java.util.jar.Pack200.Unpacker