目录
1 语法层面
1.1 文本块
- 文本块指的是多行字符串
- 使用连续的三个引号来包围一段多行的字符串
- 避免了换行转义的麻烦
- 支持String.format
public class App {
public static void main(String[] args) {
String str = """
this is mutil string
i name is %s
please see it
""";
System.out.println(String.format(str,"tom"));
}
}
1.2 switch表达式增强
- 支持表达式使用
- 多条件匹配
public class App {
public static void main(String[] args) {
String name = "James1";
switch (name){
case "James","libai" -> System.out.println("Hello "+name);
case "John","qiongsi" -> System.out.println("Hello1 "+name);
default -> System.out.println("Hello3 "+name);
}
}
}
- 使用yield关键字增加返回值
public class App {
public static void main(String[] args) {
String name = "James1";
int a = switch (name) {
case "James", "libai" -> {
System.out.println("Hello " + name);
yield 1;
}
case "John", "qiongsi" -> {
System.out.println("Hello1 " + name);
yield 2;
}
default -> {
System.out.println("Hello3 " + name);
yield 4;
}
};
System.out.println(a);
}
}
1.3 instanceof的匹配模式
- 当变量类型经过instanceof匹配目标类型时,可直接声明目标类型变量,无需要再次强转
public class App {
public static void main(String[] args) {
Object a = "123";
if (a instanceof Integer i) {
System.out.println(i.longValue());
} else if (a instanceof String s) {
System.out.println(s.charAt(1));
}
}
}
1.4 var局部变量推导
- 对于可以推导出其具体类型的局部变量,可使var修饰
public class App {
public static void main(String[] args) {
var s = "123";
System.out.println(s.charAt(1));
}
}
2 模块化以及类封装
2.1 记录类record
- 被record定义的类代表不可变的常量
- 只能在创建时指定类的属性,不能再次修改
public record Person(String name, Integer age) {
public static void main(String[] args) {
Person person = new Person("John", 30);
System.out.println(person);
System.out.println(person.age());
System.out.println(person.name());
}
}
- 反射也不能修改record类的属性,因为record类给所有属性加上了final修饰符
2.2 隐藏类Hidden Class
- 不能被其他类直接使用的类
- 隐藏类不再依赖于类加载器
- 通过读取目标字节码的方式,创建一个对其他类隐藏的class对象
- 然后通过反射的方式创建对象,调用方法
public class App {
private static String encode() throws IOException {
String classPath="C:\\jwork\\jdk17demo\\target\\classes\\com\\demo\\HiddenClass.class";
byte[] bytes = Files.readAllBytes(Paths.get(classPath));
return new String(Base64.getEncoder().encode(bytes));
}
public static void main(String[] args) throws Throwable {
String encode = encode();
byte[] decode = Base64.getDecoder().decode(encode);
MethodHandles.Lookup lookup = MethodHandles.lookup().defineHiddenClass(decode,
true, MethodHandles.Lookup.ClassOption.NESTMATE);
Class<?> aClass = lookup.lookupClass();
//获取类名
System.out.println(aClass.getName());
//获取所有方法
for (Method declaredMethod : aClass.getDeclaredMethods()) {
System.out.println(declaredMethod.getName());
}
//调用静态方法
MethodHandle printHello = lookup.findStatic(aClass, "printHello", MethodType.methodType(void.class, String.class));
printHello.invokeExact("小明");
printHello.invoke("小明");
//创建实例
MethodHandle newInstance = lookup.findConstructor(aClass, MethodType.methodType(void.class));
Object invoke = newInstance.invoke();
System.out.println(invoke);
//调用实例方法
MethodHandle sayHello = lookup.findVirtual(aClass, "sayHello", MethodType.methodType(void.class, String.class));
sayHello.invoke(invoke,"小明");
}
}
- 其中加密的方式可自由掌控,从而达到真实隐藏类的目的
2.3 密封类 Sealed Class
- jdk8中一个类要么可以被继承,要么不可以被继承(final修饰)
- jdk17中可以指定允许哪些类继承
- sealed:表示类具有密封性,必须具有子类,通过permits执行允许继承的子类
- non-sealed:表示类不具备密封性,可随意集成
- final:表示类不能被继承
public sealed abstract class Shape permits Circle, Rectangle, Square {
public abstract int lines();
}
public final class Circle extends Shape{
@Override
public int lines() {
return 0;
}
}
public non-sealed class Square extends Shape{
@Override
public int lines() {
return 0;
}
}
public sealed class Rectangle extends Shape permits FilledRectangle{
@Override
public int lines() {
return 0;
}
}
public final class FilledRectangle extends Rectangle{
}
2.4 模块化Module System
2.4.1 什么是模块化
- jdk9引入模块化机制
- 对java中package包的上一层抽象
- 包含一组密切相关的包,资源,以及一个模块描述文件
- 通过module,可以更精准的分配对象的生效范围
- jdk8安装目录下,jdk内置的功能是以jar包的形式存在的
- jdk17安装目录下,取而代之的是一系列以jmod后缀的文件,一个文件代表一个模块
- jmod文件其实就是一个tar包
- 查看jdk的模块列表
2.4.2 声明一个module
- 在模块的class根目录下创建module-info.java⽂件声明模块
- 默认情况下以项目名作为模块名
- module-info.java⽂件称之为模块描述文件
- 在module-info.java⽂件内主要包含如下内容
- 模块名
- 对其他module的依赖关系
- 当前module对外开放的API
- 使用和提供的服务
module m2 {
requires m1;
}
2.4.3 require声明模块依赖
- require用于声明当前模块需要依赖哪些外部模块
- 即除了在pom.xml中引入依赖外,还需要在module-info.java中添加配置
- 当前module在编译期间需要依赖其他module,但是在运行期间不需要依赖时,使用requires static进行依赖声明
2.4.4 exports和open声明对外的API
- 当需要暴露当前module的API提供外部module使用时,使用exports声明需要暴漏的包
- 当通过反射访问外面module的私有属性或者方法时,访问报错
- 此时需要通过open声明需要暴露的包,可以实现私有属性或者方法的访问
2.4.5 uses服务开放机制
- JDK8的SPI机制需要通过配置文件暴露提供的服务类
- JDK17重新制定了SPI机制
- 在服务提供方通过provides ... with ... 暴露服务类
- 在服务调用方通过uses ... 发现服务
2.4.6 构建模块化jar包
2.5 类加载机制调整
2.6 GC调整
2.6.1 ZGC转正
使用-XX:+useZGC参数启动zgc垃圾回收器
zgc在版本升级过程中做了很多优化,目前查看jdk17中java -XX:+PrintFlagsFinal -version可以看到关于zgc的不稳定参数已经基本没有了
2.6.2 Shenandoah垃圾回收器正式纳入jdk中
- 由RedHat推出的Shenandoah垃圾回收器集成进jdk
- 使用参数-XX:+ShenandoahGC启用
2.6.3 废除CMS
- 随着G1垃圾回收器趋于完善,并且后续ZGC,shenandoah等现代垃圾回收的开始登场
- 过于复杂的并且存在一定问题的CMS垃圾回收逐渐被淘汰
- CMS的主要问题点在于
- 内存碎片问题
- Concurrent Mode Fail之后退化为Serial垃圾回收器
- 同时作为CMS备用方案的Serial Old垃圾回收器也被废弃掉
2.7 其他调整
- 重写socket底层API代码
- 默认禁用偏向锁,可通过参数-XX:UseBiasedLocking手动开启
3 GraalVM虚拟机
3.1 关于Graal
- Graal编译器是作为HotSpot C1编译器的替换方案设计的
- 使用java语言编写
- 2012年,Graal编译器发展成为一个一个独立的java编译项目
- 早期的Graal需要与HotSpot虚拟机配合工作
- 随着JDK9推出JVMCI(Java虚拟机编译器接口),使得Graal可以从HotSpot中独立出来,并且逐渐形成了现在的GraalVM
3.2 安装GraalVM
安装与JDK一致
3.3 使用GraalVM
- GraalVM日常使用与jdk基本一致,不过重点推出了native-image命令
- native-image命令可以将java文件直接编译为不需要依赖jdk也可以执行的可执行文件
- 其采用了AOT提前编译技术,将java语言翻译为机器码指令,从而加快了其启动速度以及执行速度