8. Java8新特性-默认方法(default method)

传统上(< JDK8)接口中定义的方法都是public abstract的,都是没有实现的,实现接口的类必须为接口中定义的每一个方法提供实现,否则会有编译错误。

但一旦库的设计者需要更新接口,向其中加入新的方法,这种方式就会出现问题。 因为现存的实现类都不在库设计者的控制范围内,当项目升级JDK版本后,这些实体类为了适配更改后的接口,需要再修改,尤其是JDK8是非常重要的版本更新增加了大量方法。

所以库设计者为了避免出现大规模更改代码,方便大家升级到JDK8,引入了新的机制,即JDK8之后接口现在支持声明方法的同时提供实现,打破了接口中方法都是public abstract的约定

通过两种方式可以完成这种操作:

  1. 允许在接口中声明静态方法。
  2. 允许定义默认方法(default)。

接口的实现类如果不显式的提供默认方法的具体实现,就会自动继承默认的实现。

之前学习Stream API可以用了很多default 方法,典型的是:

  1. List接口定义的sort方法
default void sort(Comparator<? super E> c){ 
    Collections.sort(this, c); 
}
  1. Collection接口定义的stream方法
default Stream<E> stream() { 
    return StreamSupport.stream(spliterator(), false); 
}
静态方法和接口

同时定义接口和工具辅助类是Java语言常用的一种模式,工具类定义了许多和接口实例协作的静态方法,典型的如:Collection接口和Collections工具类。现在接口本身就能定义静态类,为了保持向后的兼容性,这些类还是会存在。

解决冲突的规则

Java语言中一个类只能继承一个父类,但是一个类可以实现多个接口。随着默认方法在Java 8中引入,有可能出现一个类继承了多个方法而它们使用的却是同样的函数签名。当发生这样的情况时,JDK会如何处理冲突?

示例:

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

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

public class C implements B, A { 
   public static void main(String[] args) { 
       new C().hello(); 
   } 
}

// 打印结果是什么?

解决该问题的三个规则
  1. 类中的方法优先级最高。即类中或父类中声明的方法优先级高于default方法
  2. 如果第一点无法判断,则子接口的优先级更高,即如果B继承了A,则B接口中方法优先级更高(上面示例的情况即是如此,所以会打印:Hello from B)
  3. 如果依然无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,来显式的选择一个default方法实现。

第三点举个示例:

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

public interface B { 
   default void hello() { 
       System.out.println("Hello from B"); 
   } 
} 

public class C implements B, A { 
   
   void hello() {
       B.super.hello();
   }

   public static void main(String[] args) { 
       new C().hello(); 
   } 
}

// 如上所示,当出现第三种情况时,需要显式复写冲突的方法,可在方法体中调用父接口的实现(B.super.hello())
小结

Java 8中的接口可以通过默认方法和静态方法提供方法的代码实现。

  1. 默认方法的开头以关键字default修饰,方法体与常规的类方法相同。
  2. 默认方法的出现能帮助库的设计者以后向兼容的方式演进API。
  3. 我们有办法解决由于一个类从多个接口中继承了拥有相同函数签名的方法而导致的冲突。

你可能感兴趣的:(Java基础相关,java,开发语言)