java15学习笔记

发布于:2025-08-17 ⋅ 阅读:(12) ⋅ 点赞:(0)

        Java15是一个重要的功能发布版本,它为Java带来了许多JVM特定的变化和语言特定的变化。它遵循了从Java10开始引入的Java发布节奏,并在Java14发布后的六个月后于2020年9月发布。

Java15新特性如下

339: Edwards-Curve Digital Signature Algorithm (EdDSA) 爱德华兹曲线数字签名算法
360: Sealed Classes (Preview)  封闭类(预览)
371: Hidden Classes 隐藏类
372: Remove the Nashorn JavaScript Engine 删除Nashorn JavaScript引擎
373: Reimplement the Legacy DatagramSocket API  重新实现传统DatagramSocket API
374: Disable and Deprecate Biased Locking 禁用和弃用偏置锁定
375: Pattern Matching for instanceof (Second Preview) instanceof匹配增强(第二次预览)
377: ZGC: A Scalable Low-Latency Garbage Collector Z垃圾收集器
378: Text Blocks 文本块
379: Shenandoah: A Low-Pause-Time Garbage Collector  Shenandoah垃圾收集算法
381: Remove the Solaris and SPARC Ports 删除Solaris and SPARC Ports
383: Foreign-Memory Access API (Second Incubator) 外部内存(第二次孵化)
384: Records (Second Preview) Records类(第二次预览)
385: Deprecate RMI Activation for Removal 弃用RMI

JEP 339 Edwards-Curve Digital Signature Algorithm (EdDSA)

在公钥密码学中,爱德华兹曲线数字签名算法( EdDSA ) 是一种数字签名方案,它使用基于扭曲爱德华兹曲线的Schnorr 签名变体。它被设计为比现有的数字签名方案更快而不牺牲安全性。

        在Java中,EdDSA(爱德华兹曲线数字签名算法)[ RFC 8032 ] 是在Java 15中通过JEP 339添加的另一种附加数字签名方案。它不会取代 JDK 中现有的椭圆曲线数字签名算法( ECDSA )。

        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
        KeyPair kp = kpg.generateKeyPair();
        byte[] msg = "test_string".getBytes(StandardCharsets.UTF_8);
        Signature sig = Signature.getInstance("Ed25519");
        sig.initSign(kp.getPrivate());
        sig.update(msg);
        byte[] s = sig.sign();
        String encodedString = Base64.getEncoder().encodeToString(s);
        System.out.println(encodedString);
        //KtLEZJYcqAUZ+tggEKfv0JmpEKM76ICjZb2hTivK20VQnlw9rWrD9JHjdsLGJgccNNQECrlp6GrYPIoBd5qzAg==

JEP 360 Sealed Classes (Preview)

见文章  java15学习笔记-密封类

JEP 371 Hidden Classes

隐藏类(JEP 371)是 Java 15 引入的底层机制,允许在运行时动态生成 不可发现、不可反射访问 的类,主要用于:

框架内部实现:如动态代理、字节码生成工具(如 CGLIB、Byte Buddy)。

性能优化:减少反射调用开销,避免类污染全局命名空间。

核心特性

不可发现性:无法通过类加载器或反射 API 直接访问。

生命周期隔离:与定义它们的上下文(如方法)绑定,执行结束后可被垃圾回收。

安全性增强:限制外部对动态生成代码的访问,降低反射攻击风险

不可发现性:无法通过类加载器或反射 API 直接访问。

生命周期隔离:与定义它们的上下文(如方法)绑定,执行结束后可被垃圾回收。

安全性增强:限制外部对动态生成代码的访问,降低反射攻击风险。

三、应用场景与案例
动态代理框架:
Spring AOP 使用隐藏类生成代理对象,避免类名冲突和反射开销。
代码生成工具:
Byte Buddy 在运行时生成隐藏类,用于实现 AOP、ORM 等功能。
模块化隔离:
在 JPMS 模块系统中,隐藏类可实现模块内部的私有服务。
四、与传统反射的对比

隐藏类 传统反射
可见性 仅对定义者可见 全局可见
性能 接近直接调用

有显著性能损耗

安全性 无法通过反射访问 存在反射攻击风险
生命周期 与定义上下文绑定 由类加载器管理
适用场景 框架内部实现、性能敏感 通用动态调用

五、示例代码

jar包放在了开头下载部分

    public static void main(String[] args) throws Throwable {
        byte[] bytes = generate();
        // 使用自定义的ClassLoader
        MyClassLoader cl = new MyClassLoader();
        // 加载我们生成的 HelloWorld 类
        Class clazz = cl.defineClass("HelloWorld", bytes);
        // 反射获取 main 方法
        Method main = clazz.getMethod("main", String[].class);
        // 调用 main 方法
        main.invoke(null, new Object[]{new String[]{}});
     }   
     /**
     * 自定义ClassLoader以支持加载字节数组形式的字节码
     * 
     */
    static class MyClassLoader extends ClassLoader {
        public Class defineClass(String name, byte[] b) {
            // ClassLoader是个抽象类,而ClassLoader.defineClass 方法是protected的
            // 所以我们需要定义一个子类将这个方法暴露出来
            return super.defineClass(name, b, 0, b.length);
        }
    }
    private static byte[] generate() {
        ClassWriter cw = new ClassWriter(0);
        // 定义对象头:版本号、修饰符、全类名、签名、父类、实现的接口
        cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "HelloWorld",
                null, "java/lang/Object", null);
        // 添加方法:修饰符、方法名、描述符、签名、抛出的异常
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main",
                "([Ljava/lang/String;)V", null, null);
        // 执行指令:获取静态属性
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        // 加载常量 load constant
        mv.visitLdcInsn("""
                你是我的小呀小苹果,
                怎么爱你都不嫌多
                """);
        // 调用方法
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
        // 返回
        mv.visitInsn(Opcodes.RETURN);
        // 设置栈大小和局部变量表大小
        mv.visitMaxs(2, 1);
        // 方法结束
        mv.visitEnd();
        // 类完成
        cw.visitEnd();
        // 生成字节数组
        return cw.toByteArray();
    }

JEP 372 Remove the Nashorn JavaScript Engine

删除Nashorn JavaScript脚本引擎和API,以及jjs工具。引擎、API和工具在Java 11中已被弃用,并明确表示将在未来的版本中删除。

一方面没人用,另一方面ES技术的发展难以支撑。

两个JDK模块将被永久删除:
jdk.scripting.nashorn——包含jdk.nashorn.api.scripting和jdk.nashoren.api.tree包。
jdk.scripting.nashorn.shell——包含jjs工具。

JEP 373 Reimplement the Legacy DatagramSocket API

java.net.DatagramSocket 和 java.net.MulticastSocket API 的旧实现被更简单、更现代化的实现所取代,这样更容易维护和调试。

java.net.datagram.Socket 和 java.net.MulticastSocket 的当前实现是在 JDK 1.0 中引入的,而IPv6仍在开发中。这个 JEP 的目标是替换当前的 MulticastSocket 实现,该实现以难以维护的方式调和了IPv4和IPv6。

JEP 374: Deprecate and Disable Biased Locking

默认情况下禁用偏向锁,并弃用所有相关的命令行选项。
偏向锁是锁上面又加了一个标志类型的锁,当多线程争用资源时,如果是当前线程拥有该资源,偏向锁会避免相同资源的原子操作,从而可以减少无竞争锁的开销。

当多线程以单线程方式使用的对象执行许多同步操作时,偏置锁在历史上比常规锁定技术带来了显著的性能改进。

现实情况下,不会很少甚至不会出现大量线程同步操作。少线程争用的情况下偏向锁的性能甚至不如原子操作。所以决定弃用

使用下面命令可以开启偏向锁

XX:+UseBiasedLocking。

JEP 375: Pattern Matching for instanceof (Second Preview)

这是第二次预览,第一次预览在Java14,后续在Java16正式上线

在Java14之前,instanceof主要用来检查对象的类型,检查匹配后,还需要对其进行类型强转才能使用该类型的变量,这显得很多余也很业余,而且存在手滑转错类型的可能。

java14之前 instanceof使用如下

        Object obj = "Java14Test";
        if (obj instanceof String) {
            String str = (String) obj;
            System.out.println(str);
        }

在 Java 14 中,使用模式匹配的 instanceof,这可以被简化为:

        Object obj = "Java14Test";
        if (obj instanceof String s) {
            System.out.println(s);
        }

实际使用案例

    public static void main(String[] args) throws ScriptException {
        Object obj = "Java14Test";
        Boolean b = getString(obj);
        System.out.println(b); //false
        Object obj1 = "大傻春";
        Boolean b1 = getString(obj1);
        System.out.println(b1); //true
    }    

public static Boolean getString(Object o)
    {
        return(o instanceof String string ) && string == "大傻春";
    }

注意不要和 || 一起使用 例如 

(o instanceof String string ) || string == "大傻春";
逻辑上不会出现这种逻辑,另外这种写法编译也报错

JEP 377: ZGC: A Scalable Low-Latency Garbage Collector (Production)

新的垃圾回收期ZGC简称Z垃圾回收期,虽然已经正式生产,但是还是建议使用G1为GC。

自 JDK 11 作为实验性功能引入,并在后续版本(如 JDK 15+)中逐步成熟。ZGC 的核心设计目标是 低延迟 和 大堆内存管理能力,能够将垃圾收集的停顿时间(STW, Stop-The-World)控制在 10ms 以下,甚至达到亚毫秒级。

JEP 378: Text Blocks

文本块最早是在java12提出的概念,但是被撤回JEP 326: Raw String Literals (Preview)->java13开始第一次原来->java14第二次预览->Java15正式上线

        String x = """
                 法外狂徒张三
                \s   精神支柱快乐水 \
                罗老师
                """;
        x = x+"xxx";
        System.out.println(x);

JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector (Production)

Java12开始就引入了第一版的Shenandoah GC,相比于G1它的新特性在于可以并发的进行垃圾回收,其更像是G1的下一代继承者。它们两者有着相似的堆内存堆内存堆内存布局,在初始标记、并发标记等许多阶段的处理思路上都高度一致,甚至还直接共享了一部分实现代码。

JEP 381: Remove the Solaris and SPARC Ports

目前正在开发的许多项目和功能,如Valhalla、Loom和Panama,都需要对CPU架构和操作系统特定代码进行重大更改。放弃对Solaris和SPARC端口的支持将使OpenJDK社区的贡献者能够加速开发新功能,从而推动平台向前发展。

JEP 383: Foreign-Memory Access API (Second Incubator)

引入API,使Java程序能够安全有效地访问Java堆之外的外部内存。

Foreign-Memory Access API是由JEP 370提出的,并于2019年末针对Java 14作为一个正在孵化的API。该JEP建议结合基于反馈的改进,并在Java15中重新创建API。作为此API刷新的一部分,包含了以下更改:

一个丰富的VarHandle组合子API,自定义内存访问var句柄;
通过Splitterator接口对内存段的并行处理提供有针对性的支持;
增强了对映射内存段的支持(例如,MappedMemory Segment::force);
安全的API指向支持串行限制(例如,在两个线程之间转移线程所有权);
不安全的API指向操作和取消引用来自例如本机调用的地址,或者将这些地址包装到合成内存段中。

JEP 384: Records (Second Preview)

JEP 359于2019年年中提出了记录,并于2020年初在JDK 14中作为第一次预览。此JEP建议重新预览JDK 15中的该功能,以包含基于反馈的改进,并支持Java语言中其他形式的本地类和接口。

java14学习笔记-part1-JEP 359 (record类)

JEP 385: Deprecate RMI Activation for Removal

弃用RMI激活机制,将来将进行删除。RMI激活是RMI的一个过时部分,自Java 8以来一直是可选的。RMI的任何其他部分不会被弃用。

由于一下原因,所以做出此决定。

RMI激活已过时

RMI激活大多未使用

RMI激活会带来持续的维护负担


网站公告

今日签到

点亮在社区的每一天
去签到