由于 jdk 9 和 jdk10都不是长期支持的版本,因此将它们的新特性放到 jdk 11 中讲
一、JDK 和 JRE 目录结构的改变
没有名为jre的子目录 | |
bin目录 | 包含所有命令。在Windows平台上,它继续包含系统的运行时动态链接库 |
conf目录 | 包含用户可编辑的配置文件,例如以前位于jre/bin目录中.properties和.policy文件 |
include目录 | 包含要在以前编辑本地代码时使用的C/C++头文件。它只存在于JDK中/td> |
jmods目录 | 包含JMOD格式的平台模块。创建自定义运行时映像时需要它。它只存在于JDK中/td> |
legal目录 | 包含法律声明 |
lib目录 | 包含非Windows平台上的动态连接本地库。其子目录和文件不应由开发人员直接编辑或使用 |
二、模块化系统
每次JVM启动的时候,至少会有30~60MB的内存加载,主要原因时JVM需要加载rt.jar,不管其中的类是否被classloader加载,第一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的class)。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这就会导致无意中使用了并不想被公开访问的API。
本质上将,模块(moudule)的概念,其实就是package外再裹一层,也就是说,用模块来管理各个package,通过声明某个package暴露,不声明默认就是隐藏。因此,模块化使的代码组织上更安全,因此它可以指定哪些部分可以暴露,哪些部分可以隐藏。
实现目标
- 模块化的主要目的在于减少内存的开销
- 只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开发和维护
- 改进 Java SE 平台,使其可以适应不同大小的计算设备
- 改进其安全性,可维护性,提高性能
package stars.grace.test;
import stars.grace.routine.Person;
public class ModuleTest {
public static void main(String[] args) {
Person person = new Person("Sakura",10);
System.out.println(person);
}
}
module test {
requires routine;
}
package stars.grace.routine;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
module routine {
exports stars.grace.routine;
}
三、Java的REPL工具:jShell命令
jSell工具让Java可以像脚本语言一样运行,从控制台启动jSell,利用jShell在没有创建类的情况下直接声明变量,计算表达式,执行语句。即开发时在命令行里直接运行Java的代码,而不需要创建Java文件。jShell也可以从文件中加载语句或者将语句保存到文件中。jShell也可以使用tab键进行自动补全和自动添加分号。
四、语法改进
4.1、接口的私有方法
Java 8 规定接口中的方法处理抽象方法之外,还可以定义静态方法和默认方法。一定程度上,拓展了接口的功能,此时的接口更像是一个抽象类。在 Java 9 中,接口更加的灵活和强大,连方法的访问修饰符都可以声明为private的,此时方法将不会为你对外暴露的API的一部分。
public class MyInterfaceImplements implements MyInterface{
public static void main(String[] args) {
//接口中的静态方法只能由接口自己调用
MyInterface.staticMethod();
MyInterfaceImplements myInterfaceImplements = new MyInterfaceImplements();
myInterfaceImplements.defaultMethod();
//接口的私有方法,不能在接口外部调用
//myInterfaceImplements.privateMethod();
}
@Override
public void abstractMethod() {
}
@Override
public void defaultMethod() {
System.out.println("实现类重写了接口中的默认方法");
}
}
public interface MyInterface {
//权限修饰符为public
void abstractMethod();
//权限修饰符为public
static void staticMethod(){
System.out.println("我是接口中的静态方法");
}
//权限修饰符为public
default void defaultMethod(){
System.out.println("我是接口中的默认方法");
privateMethod();
}
private void privateMethod(){
System.out.println("我是接口中的私有方法");
}
}
4.2、钻石操作符的使用升级
import java.util.ArrayList;
import java.util.Comparator;
public class Template {
public static void main(String[] args) {
//JDK 7 中的新特性:类型推断
ArrayList<String> list = new ArrayList<>();
//钻石操作符与匿名实现类在 Java 8 中不能共存,在 Java 9 中可以
Comparator<Object> comparator = new Comparator<>(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
}
}
4.3、try语句的升级
Java 8 中,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必须在try子句中初始化,否则编译不通过。
import java.io.IOException;
import java.io.InputStreamReader;
public class Template {
public static void main(String[] args) {
//Java 9 中资源关闭操作:需要自动关闭的资源的实例化可以放在try的一对小括号外、
//此时的资源属性是常量,声明为final,不可修改
InputStreamReader reader = new InputStreamReader(System.in);
try(reader){
char[] cbuf = new char[20];
int len;
if((len = reader.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
五、类型推断
在处理 var 时,编译器先是查看表达式右边的部分,并根据右边变量值的类型进行推断,作为左边变量的类型,然后将该类型写入字节码当中。var 不是关键字
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class Template {
public static void main(String[] args) {
//声明变量时,根据所赋的指,推断变量的类型
//局部变量不赋值,不能实现类型推断
var num = 10;
var list = new ArrayList<String>();
list.add("Sakura");
list.add("Mikoto");
list.add("Misaka");
for (var i : list) {
System.out.println(i);
System.out.println(i.getClass().getName());
}
//Lambda表达式和方法引用中,左边函数式接口不能声明var
//var supplier = () -> Math.random();
//var consumer = System.out::println;
//数组的静态初始化
//var array = {1,2,3,4};
}
}
不能使用类型推断的情景
- 没有初始化的局部变量的声明
- 方法的返回类型
- 方法的参数类型
- 构造器的参数类型
- 属性
- catch块