Skip to main content
 首页 » 编程设计

java 接口中缺省方法与静态方法

2022年07月19日124qq78292959

java 8 接口中缺省方法与静态方法

java 8 新增了很多新的特性,包括lambda表达式,函数接口,方法引用,流,Optional 以及接口中的静态方法与缺省方法。
本文我们深入讨论如何使用接口中的static和default方法,并通过示例展示其应用场景。

为什么需要缺省方法

与正常接口方法一样,default方法默认为public,无需显示指定public修饰符。与正常方法不同,在方法声明之前加上default关键字,同时提供实现。请看示例:

public interface MyInterface { 
      
    // regular interface methods 
      
    default void defaultMethod() { 
        // default method implementation 
    } 
} 

java 8 使用缺省方法的原因非常明显:
典型基于抽象的设计,接口拥有一个或多个实现。如果在接口中增加方法,所有实现必须也要增加该方法实现,否则无法编译。

缺省方法有效地解决了该问题。其允许在接口中增加新的方法,并自动在接口实现中可用,因此无需修改实现类。通过这种方式,无需重构之前的实现,优雅地实现了向后兼容。

缺省方法示例

为了更好理解缺省方法功能,下面通过示例实战说明。
假设有一个接口Vehicle 及其实现,为了保持示例简单,不再扩展其他内容。

public interface Vehicle { 
      
    String getBrand(); 
      
    String speedUp(); 
      
    String slowDown(); 
      
    default String turnAlarmOn() { 
        return "Turning the vehicle alarm on."; 
    } 
      
    default String turnAlarmOff() { 
        return "Turning the vehicle alarm off."; 
    } 
} 

下面定义其实现类:

public class Car implements Vehicle { 
  
    private String brand; 
      
    // constructors/getters 
      
    @Override 
    public String getBrand() { 
        return brand; 
    } 
      
    @Override 
    public String speedUp() { 
        return "The car is speeding up."; 
    } 
      
    @Override 
    public String slowDown() { 
        return "The car is slowing down."; 
    } 
} 

最后,我们定义主类,在里面创建Car实例并调用其方法:

public static void main(String[] args) {  
    Vehicle car = new Car("BMW"); 
    System.out.println(car.getBrand()); 
    System.out.println(car.speedUp()); 
    System.out.println(car.slowDown()); 
    System.out.println(car.turnAlarmOn()); 
    System.out.println(car.turnAlarmOff()); 
} 

注意,Vehicle接口中的缺省方法turnAlarmOn() 和 turnAlarmOff() 在Car类中自动可用。而且,如果后期在Vehicle接口中增加缺省方法,应用仍然可以正常运行,不是必须提供新增方法的实现。

在接口中使用缺省方法的典型场景是————为给定类型提供额外功能,无需修改其实现类。另外,也可以用于给现有的抽象方法提供实现:

public interface Vehicle { 
      
    // additional interface methods  
      
    double getSpeed(); 
      
    default double getSpeedInKMH(double speed) { 
       // conversion       
    } 
} 

多接口继承规则

缺省方法确实是非常好的特性,但有些方面需要提醒。java允许类实现多个接口,当一个类实现多个接口时,接口中定义了相同的缺省方法会怎么?
为了更好理解,我们定义新的Alarm 接口并重构Car类:

public interface Alarm { 
  
    default String turnAlarmOn() { 
        return "Turning the alarm on."; 
    } 
      
    default String turnAlarmOff() { 
        return "Turning the alarm off."; 
    } 
} 

该接口定义了一组缺省方法,Car类实现Vehicle和Alarm两个接口:

public class Car implements Vehicle, Alarm { 
    // ... 
} 

这种情况下,代码不能编译,因为多接口继续引起冲突————菱形问题。Car类继承两组缺省方法,其不知道调用哪一个。

为了解决这种歧义问题,我们需要提供该方法的显示实现:

@Override 
public String turnAlarmOn() { 
    // custom implementation 
} 
      
@Override 
public String turnAlarmOff() { 
    // custom implementation 
} 

我们也可以在类中使用其中一个接口的缺省方法,下面看示例使用Vehicle接口:

@Override 
public String turnAlarmOn() { 
    return Vehicle.super.turnAlarmOn(); 
} 
  
@Override 
public String turnAlarmOff() { 
    return Vehicle.super.turnAlarmOff(); 
} 

类似的,也可以使用Alarm接口的缺省方法:

@Override 
public String turnAlarmOn() { 
    return Alarm.super.turnAlarmOn(); 
} 
  
@Override 
public String turnAlarmOff() { 
    return Alarm.super.turnAlarmOff(); 
} 

甚至Car类可以使用两个接口的缺省方法:

@Override 
public String turnAlarmOn() { 
    return Vehicle.super.turnAlarmOn() + " " + Alarm.super.turnAlarmOn(); 
} 
      
@Override 
public String turnAlarmOff() { 
    return Vehicle.super.turnAlarmOff() + " " + Alarm.super.turnAlarmOff(); 
} 

静态接口方法

除了在接口中声明缺省方法,java8也允许我们在接口中定义static方法实现。static方法不属于特定对象,不属于实现接口的类API的一部分,只能通过接口名称直接调用。
为了理解static方法,我们重构Vehicle接口并增加static方法:

public interface Vehicle { 
      
    // regular / default interface methods 
      
    static int getHorsePower(int rpm, int torque) { 
        return (rpm * torque) / 5252; 
    } 
} 

在接口中定义static方法与在类中定义static方法一样,而且也可以在其他static方法和default方法中调用它们。假如,我们需要在计算给定类型计算其马力,仅需要调用getHorsePower方:

Vehicle.getHorsePower(2500, 480)); 

静态接口方法背后的思想是提供一种简单的机制,允许将相关的方法放在一起,而不必创建对象,从而提高设计的内聚性。
抽象类也可以实现同样功能,主要差异是抽象类可以有构造函数、状态以及行为。静态方法可以实现对相关功能方法进行分组,无需在其实现类中定义静态方法占位符。

总结

本文我们深入讨论java 8 中如何使用接口中的static和default方法。乍一看,这个特性可能看起来有些草率,特别是从纯粹面向对象主义者的角度来看。理想情况下,接口不应该封装行为,而只应该定义某种类型的公共API。
但是,在维护与现有代码的向后兼容性方面,静态和默认方法是一种很好的折衷。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/85079730
阅读延展