Java8 新特性(一)- 接口增强

本章目录

  • Part One:接口默认方法
  • Part Two:接口静态方法

随着16年Android N的发布,Google宣布Android正式开始支持Java8。不过一直有点懒,拖啊拖,直到Java9已经出了不少日子了,才开始学Java8新特性~老实说,有点惭愧。
另外,Lambda表达式和方法引用越来越被大家熟悉使用,尤其是Rx全家桶里,再不好好学,代码都快看不懂了,顺道的把Java8的所有新特性也都研究一遍吧。


Part One:接口默认方法

从Java8开始,在接口中可以添加一个或者多个使用default关键字修饰的非抽象方法,就是接口的默认方法。默认方法可以让我们的软件接口增加新的方法,并且保证老版本的兼容性。
在Java8中,官方提供的API里就使用了默认方法,但是我们在调用这些API的时候,并没有感觉到跟以前的使用有什么不同之处,这就是默认方法的作用。例如, Iterator接口:


Java8 新特性(一)- 接口增强_第1张图片
Iterator接口.png
  1. 默认方法的简单实现
    暂时不考虑一些额外的干扰因素,只是实现简单的默认方法并不复杂,代码如下:
package cn.tmooc.tarena;

interface Person{
    void eat();
    
    void sleep();
    
    /**
     * 接口的默认方法,获取人体的BMI指数
     * @param height    米
     * @param weight    公斤
     * @return
     */
    default float getBMI(float height, float weight) {
        return weight / (float)Math.pow(height, 2);
    }
}

class Student implements Person{

    @Override
    public void eat() {
        System.out.println("学生去食堂吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("学生去宿舍睡觉");
    }
    
}

class Parent implements Person{

    @Override
    public void eat() {
        System.out.println("家长回家吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("家长回家睡觉");
    }
    
}

public class InterfaceSample {
    public static void main(String[] args) {
        Person student = new Student();
        student.eat();
        student.sleep();
        //调用接口的默认方法
        float bmi = student.getBMI(1.83F, 100);
        System.out.println("student的BMI指数 = " + bmi);
        System.out.println("==============================");
        Person mom = new Parent();
        mom.eat();
        mom.sleep();
        System.out.println("mom的BMI指数 = " + mom.getBMI(1.60F, 50));
    }
}

其中,Person是一个人类接口,定义了两个普通方法和一个默认方法。而它的子类Student和Parent都必须实现普通方法,默认方法自动继承了,可直接调用。
最后的结果如下:


Java8 新特性(一)- 接口增强_第2张图片
接口默认方法结果.png

默认方法的修改(增删改)都不会影响到已经存在的接口的编译,但是使用之前一定要仔细考虑是不是真的需要使用默认方法,因为在层级很复杂的情况下很容易引起模糊不清甚至变异错误。

  1. 多重继承的冲突原则
    由于一个方法可以从不同的接口引入,那么冲突就不可避免的,最简单的两条是
    2.1 子接口的优先级更高,即如果接口之间有继承关系,子接口的默认方法会覆盖父接口的默认方法;
    2.2 类中的方法优先级最高, 即实现类中重写了默认方法,那么以实现类为主;
package cn.tmooc.tarena;

interface A {
    default void hello() {
        System.out.println("Hello from A!");
    }
    
    default void hi() {
        System.out.println("Hi from A!");
    }
}

interface B extends A {
    default void hello() {
        System.out.println("Hello from B!");
    }
    
    default void hi() {
        System.out.println("Hi from B!");
    }
}

public class InterfaceSample implements B, A {
    
    @Override
    public void hi() {
        System.out.println("Hi from InterfaceSample!");
    }

    public static void main(String[] args) {
        InterfaceSample sample = new InterfaceSample();
        sample.hello(); //子接口的优先级更高,所以结果为Hello from B!
        sample.hi(); //类中的方法优先级最高,所以结果为Hi from InterfaceSample!
    }
}

2.3 如果两个同级的接口,具有相同的方法,那么需要显示指定到底调用哪个方法。例如,两个同级的接口都有hello方法


Java8 新特性(一)- 接口增强_第3张图片
同级接口冲突.png

代码会报错,解决方法就是让类实现某一个接口的该方法,使其具有更高的优先级即可。

  1. 默认方法不能重写Object方法
    例如我们重写了toString方法,会报以下错误:


    Java8 新特性(一)- 接口增强_第4张图片
    默认方法重写.png
  2. Java8中抽象类和接口的异同
    相同点:
    都是抽象类型的;
    都可以有具体的实现方法;
    都可以不需要实现类或者继承者去实现所有方法;
    不同点:
    声明时使用的关键字不同;
    抽象类不可以多重继承,接口可以;
    抽象类和接口所反映出的设计理念不同。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系;
    接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量可以是任意类型的,其值可以在子类中重新定义,也可以重新赋值。

Part Two:接口静态方法

Java8为接口新增静态方法后,可以把常用的工具方法直接写在接口上,可以更好地组织代码,更易阅读和使用。
例如,在官方的Comparator接口里就提供了一个静态比较方法:


Java8 新特性(一)- 接口增强_第5张图片
Comparator.png

写法上和默认方法没啥区别,就是修饰符不太一样,这里不再赘述了就。

你可能感兴趣的:(Java8 新特性(一)- 接口增强)