Java 15 新特性 (EOL)
生命周期结束时间(EOL): 2021/12/14
官方发布介绍页面:https://openjdk.org/projects/jdk/15/
1. 隐藏类
Hidden Classes 是一种新的类,专门用于框架生成的类,不能被字节码直接引用。
我们创建一个隐藏类的步骤如下:
第一步:先创建一个普通的Java类
public class JEP371HiddenClasses {
public static String hello() {
return "hello, hidden classes.";
}
}
第二步:编译一下,或得编译后的class文件。然后使用Base64对文件内容进行编码,你可以用各种工具,也可以用下面代码来获取:
// 将字节码文件读取成字节流数组
String filePath = "JEP371HiddenClasses.class";
byte[] b = Files.readAllBytes(Paths.get(filePath));
// 使用Base64对字节流数组进行编码
log.info(Base64.getEncoder().encodeToString(b));
上方的log.info执行后会输出一段base64编码后的字符串,该字符串就是隐藏类的字节码,我们只需要将其复制下来并粘贴到我们项目中,推荐用yml文件存储。
第三步:通过反射加载上面生成的类,并调用隐藏类中的hello函数,代码如下:
@Test
void testHiddenClasses() throws Throwable {
// 1. 加载encode之后的隐藏类
String CLASS_INFO = "隐藏类的base64编码字符串";
byte[] classInBytes = getDecoder().decode(CLASS_INFO);
Class<?> proxy = MethodHandles.lookup()
.defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
.lookupClass();
// 输出类名
log.info(proxy.getName());
// 输出类有哪些函数
for(Method method : proxy.getDeclaredMethods()) {
log.info(method.getName());
}
// 2. 调用hello函数
MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "hello", MethodType.methodType(String.class));
String result = (String) mh.invokeExact();
log.info(result);
}
这里的CLASS_INFO内容就是上一步我们处理好的隐藏类内容,先通过Base64将该内容解码,然后通过反射机制来将这个隐藏类的代理创建出来。
可以看到这里创建隐藏类的时候用的是java.lang.invoke.MethodHandles.Lookup#defineHiddenClass,而创建普通类则是用ClassLoader::defineClass的。而这里的三个参数分别是:
bytes:符合java虚拟机规范的字节码initialize:是否要初始化类options:java类的类型,详见java.lang.invoke.MethodHandles.Lookup.ClassOption
再下面的操作就是对这个类的一些内容输出和方法执行。最后我们可以尝试执行下这个测试内容,最终会获得如下输出:
11:23:20.544 [main] INFO cn.com.rydeen.jdk.JEP371Test - cn.com.rydeen.jdk.JEP371HiddenClasses/0x0000000800cb0c00
11:23:20.545 [main] INFO cn.com.rydeen.jdk.JEP371Test - hello
11:23:20.545 [main] INFO cn.com.rydeen.jdk.JEP371Test - hello, hidden classes.
- 第一行:输出了这个隐藏类的类名
- 第二行:输出了这个隐藏类下的方法名称
- 第三行:调用隐藏类下的hello方法获得的返回内容
2. 文本块
文本块在 JDK 15 中成为标准特性,允许在多行字符串中使用更简洁的语法。
String textBlock = """
Hello,
World!
""";
System.out.println(textBlock);
3. instanceof 模式匹配 (第二次预览)
instanceof 模式匹配简化了类型检查和转换。
Object obj = "Hello, World!";
if (obj instanceof String s) {
System.out.println(s.toLowerCase()); // hello, world!
}
4. 记录类 (第二次预览)
Records 提供了一种简洁的方式来定义不可变数据类。
public record Point(int x, int y) {}
Point point = new Point(1, 2);
System.out.println(point.x()); // 1
System.out.println(point.y()); // 2
5. 密封类 (第一次预览)
Sealed Classes 允许类或接口限制哪些其他类或接口可以扩展或实现它们。
public abstract sealed class Shape permits Circle, Square {}
public final class Circle extends Shape {
// Implementation
}
public final class Square extends Shape {
// Implementation
}
6. ZGC: 可伸缩的低延迟垃圾收集器
ZGC 现在是一个生产级别的垃圾回收器,支持多种平台。
// 使用命令行参数来启用 ZGC
// -XX:+UseZGC
7. 外部函数和内存API(第二次孵化)
引入了外部内存访问 API,允许 Java 程序安全高效地访问外部内存。
8. 新增 Edwards-Curve 数字签名算法 (EdDSA)
支持 Edwards-Curve 数字签名算法 (EdDSA)。
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
public class EdDSAExample {
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update("test message".getBytes());
byte[] signature = sig.sign();
sig.initVerify(kp.getPublic());
sig.update("test message".getBytes());
boolean verified = sig.verify(signature);
System.out.println("Signature verified: " + verified); // Signature verified: true
}
}