Java新版特性企业级详解七(Java15)

本文为【Java新版特性企业级详解】系列文章合集之一,旨在介绍java8-18全部更新功能,本文为第7篇

Java新版特性企业级详解7(Java15)新特性

2020年9月15日,java15正式发布,(风平浪静的一个版本)共有14个JEP,是时间驱动形式发布的第六个版本。相关文档: https://openjdk.java.net/projects/jdk/15/

行文到这里,我们再来简单回顾一下java每个版本的主要特征:

JDK5 :enum 泛型 自动装箱拆箱 可变参数 增强循环;

JDK6 : 支持脚本语言 JDBC4.0API;

JDK7 :支持trycatch-with-resources switch语句新增String支持 NIO2.0;

JDK8 : lambda StreamAPI 新的时间日期API 方法引用 构造器引用;

JDK9 :模块化 jShell;

JDK10:局部变量类型推断;

JDK11:ZGC Epsilon GC;

JDK12:switch表达式 ShenandoahGC 增强G1;

JDK13:switch表达式引入 yield 文本块;

JDK14:instanceof类型识别 Records 弃用ParallelScavenge+Serial GC组合 删除CMS;

各个版本JEP的数量:

接下来说一下Java15更新内容。

密封类(预览)

通过密封的类和接口来增强Java编程语言,这是新的预览特性,用于限制超类的使用,密封的类和接口限制其他可继承或者实现他们的其他类或接口。

目标:

  1. 允许类或接口的开发者来控制那些类能够实现,提供了比限制使用超类的访问修饰符声明方式更多选择。
  2. 在java中,类层次构造通过集成实现代码的重用,父类的方法可以被许多子类继承。但是,类层次接口的目的并不总是重用代码。有时是对域中存在的各种可能性进行建模,例如图形库支持的形状类型。当以这种方式使用类层次结构,我们可能需要限制子类集,从而简化建模。
  3. 虽然我们可以通过final来限定子类继承,但是这是绝对杜绝类子类,而类的密封是允许子类,但是限定是那个或者哪些。

使用方式:

引入 Seald class或interface,这些class或者interface只允许被指定的类或者interface进行扩展和实现。

使用修饰符sealed,我们可以将一个类声明为密封类。密封类使用reserved关键字permits列出可以直接扩展他的类。子类可以是最终的,非密封或者密封的。

/*sealed 对Person类进行密封 * permits 指明哪些类可以继承 * 子类必须是final修饰的或者也是密封的 * 如果子类不想被密封,可以使用non-sealed修饰 * */sealed class Person permits Worker, Teacher, Cook, Boss, Employee, Student {}final class Cook extends Person {}final class Boss extends Person {}final class Employee extends Person {}final class Teacher extends Person {}// 密封的子类允许继续有子类sealed class Student extends Person permits PrimaryStudent, GraduateStudent {}final class PrimaryStudent extends Student {}final class GraduateStudent extends Student {}// 通过non-sealed取消子类密封non-sealed class Worker extends Person {}class CarWorker extends Worker {}

密封接口,指定实现类的接口:

/* * 只有接口可以继承接口 * 一个接口可以同时继承多个接口 * final不能修饰接口,密封接口在被继承时,子接口要么使用 sealed non sealed  修饰 * */sealed interface Myinter1 permits Myinter3 {}sealed interface Myinter2 permits Myinter3 {}sealed interface Myinter3 extends Myinter1, Myinter2 {}non-sealed class MyImpl implements Myinter3 {}sealed interface I permits A, B, C {}final class A implements I {}sealed class B implements I {}non-sealed class C implements I {}final class D extends B {}

注意:密封接口不可以使用匿名内部类进行实现。

密封列与接口和类型匹配问题

class TestSealedClass {  public static void main(String[] args) {    test(new C());  }  public static void test(C c) {    if (c instanceof I) {      System.out.println("it is an i");    } else {      System.out.println("it is not i");    }  }}interface I {}sealed class C implements I permits D, E {}non-sealed class D extends C {}final class E extends C {}// 密封类仅仅是控制类的继承和实现关系,不会影响我们的类型匹配

密封接口和records:record是隐匿式的final,可以直接实现密封接口:

class TestRecords {  public static void main(String[] args) {    MyInter1 myInter1 = new Person(10, "旋涡刘能");  }}sealed interface MyInter1 {  public void eat();}/*record 默认继承的 java.lang.Record * record可以直接实现密封接口,不需要用sealed 修饰 non-sealed 修饰 * record本身是隐式的final修饰 * * */record Pperson(Integer pid, String pname) imlements MyInter1 {  @Override  public void eat() {}}record Student(Integer pid, String pname) implements MyInter1 {  @Override  public void eat() {}}record Cook(Integer pid, String pname) implements MyInter1 {  @Override  public void eat() {}}record Worker(Integer pid, String pname) implements MyInter1 {  @Override  public void eat() {}}

隐藏类

该提案通过启用标准API来定义无法发现且有有限生命周期的隐藏类,从而提高JVM上所有语言的效率。

JDK内部和外部的框架将能够动态生成类,而这些类可以定义隐藏类。通常来说基于JVM的很多语言都有动态生成类的机制,这样可以提高语言的灵活性和效率。

  • 隐藏类天生为框架设计的,在运行时生成内部的class;
  • 隐藏类只能通过反射访问,不能直接被其他类的字节码访问;
  • 隐藏类可以独立于其他类加载,卸载,这样可以减少框架的内存占用。

什么是Hidden Class?

就是不能直接被其他class的二进制代码使用的clas。主要被一些框架用来生成运行时类,但是这些类不能被用来直接使用的,是通过反射来调用的。

比如JDK8中引入的lambda表达式,编译时不会将lambda表达式转换为专门的类,而是在运行时将相应的字节码动态生成相应的类对象,另外使用动态代理也可以为某些类生成新的动态类。

特征:

  • 不可发现性:因为我们是为某些静态的类动态生成的动态类,所以我们希望这个动态生成的类看作是静态类的一部分,所以我们不希望除了该静态类以外的其他机制发现。
  • 访问控制:我们希望在访问控制静态类的同时,也能控制到动态生成的类。
  • 生命周期:动态生成类的声明周期一般都比较短。我们不需要将其保存和静态类的生命周期一致。

API支持:

java.lang.reflect.Proxy 可以定义隐藏类作为实现代理接口的代理类。

java.lang.invoke.StringConcatFactory可以生成隐藏类来保存常量连接方法。

java.lang.invoke.LambdaMetaFactory可以生成隐藏的nestmate类,以容纳访问封闭变量的lambda主体。

instanceof类型匹配(预览)

JAVA 14中作为预览语言功能引入instanceof模式匹配,在JAVA15中出于第二次预览,而没有任何更改,回顾JAVA14即可。

Records(预览)

Records Class 第二次预览。

JDK14中引入了Records,只用一个Records可以很方便的创建一个常量类,就是一个数据的透明持有类,简化专门用于存储数据的类的创建语法 。

当声明一个Record时,该类将自动获取的内容:

  • 一个equals的实现;
  • 一个hashcode的实现;
  • 一个toString的重现;
  • 一个全参构造方法;
  • 对应声明的所有final修饰的成员变量。

文本块(确定)

JAVA13开始引入文本块,JAVA14 进行二次预览,JAVA15中成为一个正式的标准,参照JAVA14中的文本块回顾即可。

ZGC功能(确定)

JEP377:ZGC :A Scalable Low_Latency Garbage Collector ZGC 功能成为正式标准。

ZGC是JAVA11 引入的新的垃圾收集器,经历了多个阶段,自从终于成正式特性自2008年以来,ZGC已经增加了许多改进,并发类卸载,取消未使用的内存,对类数据实现共享的支持到NUMA感知,此外,最大的堆从4T增加到了16T,支持平台包括Linux,Windows和MacOS。

ZGC 是一个重新设计的并发垃圾收集器,通过GC停顿时间来提高性能,但是这并不是替换默认的G1垃圾收集器,只不过之前需要-XX:+UnlockExperimentalVMOptions -XX:+UseZGC,现在只需要-XX:+UseZGC就可以,相信不久的将来它必然会成为默认的垃圾回收器。

相关的参数有:

ZAllocationSpikeToleranceZCollectionInterval ZFragmentationLimit ZMarkStackSpaceLimit ZProcative ZUncommit ZunCommitDelay ZGC-specific JFR events(ZAllocationStall ZPageAllocation ZPageCacheFlush ZRelocationSet ZRelocationSetGroup Zuncommit ) 也从experimental变为product

ShenandoahGC垃圾收集算法转正

Shenandoah垃圾回收算法终于从实验特性转变为产品特性。

这是一个JAVA12引入的回收算法,该算法通过正在运行的JAVA线程同时进行疏散工作来减少GC暂停时间。Shenandoah的暂停时间与堆大小无关,无论是200M还是200G,都具有机会一致的暂停时间。

Shenandoah 和ZGC 对比:

  • 相同:性能几乎认为是相同的;
  • 不同:ZGC是OracleJDK的,而Shenandoah只存在于OpenJDK中,因此使用时需要注意JDK版本。

打开方式:使用-XX:+UseShenandoahGC命令行参数打开。

Shenandoah在JDK12作为experimental引入,在JDK15变为Production,之前需要通过-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC,现在只需要-XX:+UseShenandoahGC。

edDSA签名算法

这是一个新功能,新加基于EdWardS-Curve 数字签名算法,与JDK中现有的签名方案相比,EdDSA具有更高的安全性和性能,因此备受关注。

它已经在OpenSSL和BoringSSL等加密库中得到支持,在区块链领域用的比较多。

EdDSA是一种现代椭圆曲线方案,具有JDK中现有签名方案的优点,EdDSA将只在SunECMA提供中实现。

禁用偏向锁定

在默认情况下禁用偏向锁定,并弃用所有的相关命令选项。

目标是确定是否需要继续支持偏置锁定的高维护成本的遗留同步优化。HotSpot虚拟机使用该优化来减少非竞争锁的开销。

尽管某些JAVA应用程序在禁用偏向锁后可能会出现性能下降,但是偏向锁的性能提高通常不像以前那么明显。

该特性默认禁用了 biased locking(-XX:+UseBisaedLocking),并且废弃了所有相关的命令行选型(BiasedLockingStartupDelay,BiasedLockingBulkRebiasThreshold,BiasedLockingBulkRevokeThreshold,BiasedLockingDecayTime,UseOptoBiasInlining,PrintBisasedLockingStatistics and PrintPreciseBiasedLockingStatistics)

重新实现SocketAPI

作为JEP353的后续,该方案重新实现了遗留的套接字API. java.net.datagram.Socket 和java.netMulticastSocket的当前实现可以追溯到JDK1.0,当时IPV6还在开发中。

因此,当前的套接字实现尝协调和IPV4和IPV6。

具体情况:

  1. 替换 java.net.datagram 的基础实现,重新实现旧版DatagramSocket API;
  2. 简化java.net.DatagramSocket和java.net.MulticastSocket ,最新底层实现,提高了JDK的可维护性和稳定性;

新的实现:

  1. 易于维护和调试;
  2. Project Loom中正在探索虚拟线程协同。

外部存储API

目的是引入一个API。以允许java程序安全,有效地访问JAVA对之外的外部存储器,如本机,持久和托管堆。

Foreign-Memory Access API在JDK14中作为 incubating API引入,在JDK15中出于 Second Incubator,提供了改进。


Java专业人士 原创文章

请【关注】【点赞】【收藏】

如需转载,请回复说明

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章