17.Java 11 的新特性

由于 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;
}

17.Java 11 的新特性

三、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块
上一篇:第17章操 作 图 像


下一篇:279.完全平方数