本章目录
- Part One:接口默认方法
- Part Two:接口静态方法
随着16年Android N的发布,Google宣布Android正式开始支持Java8。不过一直有点懒,拖啊拖,直到Java9已经出了不少日子了,才开始学Java8新特性~老实说,有点惭愧。
另外,Lambda表达式和方法引用越来越被大家熟悉使用,尤其是Rx全家桶里,再不好好学,代码都快看不懂了,顺道的把Java8的所有新特性也都研究一遍吧。
Part One:接口默认方法
从Java8开始,在接口中可以添加一个或者多个使用default关键字修饰的非抽象方法,就是接口的默认方法。默认方法可以让我们的软件接口增加新的方法,并且保证老版本的兼容性。
在Java8中,官方提供的API里就使用了默认方法,但是我们在调用这些API的时候,并没有感觉到跟以前的使用有什么不同之处,这就是默认方法的作用。例如, Iterator接口:
Iterator接口.png
- 默认方法的简单实现
暂时不考虑一些额外的干扰因素,只是实现简单的默认方法并不复杂,代码如下:
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都必须实现普通方法,默认方法自动继承了,可直接调用。
最后的结果如下:
接口默认方法结果.png
默认方法的修改(增删改)都不会影响到已经存在的接口的编译,但是使用之前一定要仔细考虑是不是真的需要使用默认方法,因为在层级很复杂的情况下很容易引起模糊不清甚至变异错误。
- 多重继承的冲突原则
由于一个方法可以从不同的接口引入,那么冲突就不可避免的,最简单的两条是
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方法
同级接口冲突.png
代码会报错,解决方法就是让类实现某一个接口的该方法,使其具有更高的优先级即可。
-
默认方法不能重写Object方法
例如我们重写了toString方法,会报以下错误:
默认方法重写.png
- Java8中抽象类和接口的异同
相同点:
都是抽象类型的;
都可以有具体的实现方法;
都可以不需要实现类或者继承者去实现所有方法;
不同点:
声明时使用的关键字不同;
抽象类不可以多重继承,接口可以;
抽象类和接口所反映出的设计理念不同。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系;
接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量可以是任意类型的,其值可以在子类中重新定义,也可以重新赋值。
Part Two:接口静态方法
Java8为接口新增静态方法后,可以把常用的工具方法直接写在接口上,可以更好地组织代码,更易阅读和使用。
例如,在官方的Comparator接口里就提供了一个静态比较方法:
Comparator.png
写法上和默认方法没啥区别,就是修饰符不太一样,这里不再赘述了就。








网友评论