3、多版本兼容 jar 包(这个在处理向下兼容方面,非常好用)
当一个新版本的 Java 出现的时候,你的库用户要花费数年时间才会
切换到这个新的版本。这就意味着库得去向后兼容你想要支持的最老
的 Java 版本(许多情况下就是 Java 6 或者 Java7)。这实际上意味着
未来的很长一段时间,你都不能在库中运用 Java 9 所提供的新特性。
幸运的是,多版本兼容 jar 功能能让你创建仅在特定版本的 Java 环境
中运行库程序选择使用的 class 版本
案例:略
4、语法改进:接口的私有方法
在 Java 9 中,接口更加的灵活和强大,连方法的访问权限修饰符
都可以声明为 private 的了,此时方法将不会成为你对外暴露的 API
的一部分(个人认为,这肯定是JDK8遗漏了的一个点,哈哈)
看个例子:
public static String staticFun() { privateFun(); return ""; } default String defaultFun() { privateFun(); return ""; } private static void privateFun() { System.out.println("我是私有方法~"); }
这样子是没有问题,可以正常调用和使用的。但是需要注意一下两点
- 私有方法可以是static,也可以不是。看你需要default方法调用还是static方法调用
- 私有方法只能用private修饰,不能用protected。若不写,默认就是public,就是普通静态方法了。
default String defaultFun() { privateFun(); return ""; } private void privateFun() { System.out.println("我是私有方法~"); }
4、语法改进:钻石操作符(Diamond Operator)使用升级 泛型
在 java 8 中如下的操作是会报错的:
public static void main(String[] args) { Set<String> set1 = new HashSet<>(); //最常用的初始化 //Set<String> set2 = new HashSet<>(){}; //在JDK8中报错 Set<String> set2 = new HashSet<String>(){}; //这样在JDK8中也正常 Set<String> set3 = new HashSet<String>(){{}}; //这样也都是正常的 }
由此课件,报错的那种情况是因为在JDK8中,还不能直接推断出钻石操作符里面的类型而报错。而我们在JDK9以后,就可以直接这么写了:
public static void main(String[] args) { Set<String> set1 = new HashSet<>(); //最常用的初始化 Set<String> set2 = new HashSet<>(){}; //在JDK8中报错 Set<String> set3 = new HashSet<>(){{}}; //这样也都是正常的 }
这样写都是不会报错,可以直接书写使用的。相当于直接创建了一个HashMap的子类。
5、语法改进:UnderScore(下划线)使用的限制
这个点非常的小。距离说明就懂了
在Java8中,我们给变量取名直接就是_
public static void main(String[] args) { String _ = "hello"; System.out.println(_); //hello }
我们很清晰的看到,Java8其实给出了提示,但是编译运行都是能通过的,而到了Java9:
直接就提示_是关键字,编译都过不了了。
6、底层结构:String 存储结构变更(这个很重要)
UTF-8表示一个字符是个动态的过程,可以能用1、2、3个字节都是有可能的。但是UTF-16明确的就是不管你是拉丁文、中文等,都是恒定的用两个字节表示
JDK8的字符串存储在char类型的数组里面,不难想象在绝大多数情况下,char类型只需要一个字节就能表示出来了,比如各种字母什么的,两个字节存储势必会浪费空间,JDK9的一个优化就在这,内存的优化。
Java8:
private final char value[];
Java9:
private final byte[] value;
结论:String 再也不用 char[] 来存储啦,改成了 byte[] 加上编码标
记,节约了不少空间。由于底层用了字节数组byte[]来存储,所以遇上非拉丁文,JDK9配合了一个encodingFlag来配合编码解码的
so,相应的StringBuffer 和 StringBuilder 也对应的做出了对应的变化。
有的人担心,这会不会影响到我的charAt方法呢?那我们来看看:
public static void main(String[] args) { String str = "hello"; String china = "方世享"; System.out.println(str.charAt(1)); //e System.out.println(china.charAt(1)); //世 }
显然,这个对上层的调用者是完全透明的,完全是底层的数据结构存储而已。但是有必要对比一下源码,还是有非常大的区别的:
java8的charAt方法源码: 实现起来简单很多吧
public char charAt(int index) { if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; }
java9的charAt方法源码:
public char charAt(int index) { if (isLatin1()) { return StringLatin1.charAt(value, index); } else { return StringUTF16.charAt(value, index); } }