Java8新特性之默认方法和静态方法

作者:编码是个技术活 时间:2021-08-29 13:34:26 

前言

在Java 8之前,默认情况下,接口中的所有方法都是公共的和抽象的。但是这一限制在Java 8中被打破了,Java 8允许开发人员在接口中添加新方法,而无需在实现这些接口的类中进行任何更改。

为什么会有默认方法?

主要是为了方便扩展已有接口;如果没有默认方法,假如给Java中的某个接口添加一个新的抽象方法,那么所有实现了该接口的类都得修改,影响将非常大。

举个例子,Sortable <T>接口以及实现该接口的类SortableNumberCollection和SortableStringCollection。该接口有两种方法:void sort(); 和T peek()。


public interface Sortable<T> {
void sort();
T peek();
}

sort()方法用于对象排序,T peek()用于获取指定元素,另外需要一个比较器类ObjectComparator来对对象进行排序。


public class ObjectComparator implements Comparator<Comparable> {
@Override
public int compare(Comparable o1, Comparable o2) {
 return o1.compareTo(o2);
}
}

SortableStringCollection是一个自定义集合类可以进行排序,并查看字符串指定元素,代码如下:


public class SortableStringCollection implements Sortable<String> {

private List<String> items = new ArrayList<>();

public void add(String item) {
 items.add(item);
}

@Override
public void sort() {
 items.sort(new ObjectComparator());
}

@Override
public String peek() {
 return items.get(0);
}
}

同样,SortableNumberCollection是一个自定义集合类,其中包含可以使用接口方法进行排序和查看的数字列表指定元素,代码如下:


public class SortableNumberCollection implements Sortable<Integer> {

private List<Integer> items = new ArrayList<>();

public void add(Integer item) {
 items.add(item);
}

@Override
public void sort() {
 items.sort(new ObjectComparator());
}

@Override
public Integer peek() {
 return items.get(0);
}
}

在Java8之前如果对接口Sortable<T>添加新方法:T sortAndPeek(),那么SortableStringCollection和

SortableNumberCollection都必须实现T sortAndPeek()方法。

Java8之后提供了一种新的实现方式,默认方法 default method,我们可以对Sortable<T>进行如下改造:


public interface Sortable<T> {
void sort();
T peek();

default T sortAndPeek(){ // New 'default method' added in the interface
 sort();
 return peek();
}

}

同时SortableStringCollection和SortableNumberCollection类不需要任何更改。这样可以减少我们对原有代码的改动。同时如果需要,还可以在实现此接口的任何类中重写该方法T sortAndPeek()的默认实现。

在下图中我们看到default Method不通的标识:

Java8新特性之默认方法和静态方法

在多继承中使用默认方法问题

如果两个或多个接口具有相同的默认方法签名,并且一个类实现了这两个接口,则将引发编译时错误。例如:


public interface Interface1 {
void methodOne(String str);
default void newMethod(){
 System.out.println("Interface1: Newly added method");
}
}

public interface Interface2 {
void methodTwo(String str);
default void newMethod(){
 System.out.println("Interface2: Newly added method");
}
}

public class InterfaceImplementation implements Interface1, Interface2{
@Override
public void methodOne(String str) {
 System.out.println("Overridden methodOne: " + str);
}

@Override
public void methodTwo(String str) {
 System.out.println("Overridden methodTwo: " + str );
}
}

此时代码会提示如下异常:

InterfaceImplementation inherits unrelated defaults for newMethod() from types Interface1 and Interface2

要解决此问题,我们将必须重写类InterfaceImplementation中的方法:


public class InterfaceImplementation implements Interface1, Interface2{
@Override
public void methodOne(String str) {
 System.out.println("Overridden methodOne: " + str);
}

// newMethod implemented to resolve the conflict.
@Override
public void newMethod() {
 System.out.println("InterfaceImplementation: Newly added method");
}

@Override
public void methodTwo(String str) {
 System.out.println("Overridden methodTwo: " + str );
}
}

我们总结一下:

  • 类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。

  • 如果无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。

  • 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,显式地选择使用哪一个默认方法的实现。

在Java 8中添加静态方法

接口定义的静态方法独立于任何对象调用。所以,在调用静态方法时,不需要实现接口,也不需要接口的实例,

就像“默认方法”一样,“静态方法”也可以添加到接口中。例如,我们可以添加一个静态方法Direction getDefaultDirection(),该方法将返回默认Direction,例如:


public interface Sortable<T> {

Direction defaultDirection = Direction.DESC;

enum Direction {
 ASC,
 DESC
};

void sort();
T peek();

static Direction getDefaultDirection(){ // 'static method' added to the interface.
 return defaultDirection;
}
}

在上面的示例中,可以使用类引用来调用静态Direction getDefaultDirection()方法:


Sortable.getDefaultDirection()

对默认方法和静态方法的一点思考

接口是设计模式中一种开闭原则的体验,而java8赋予了接口新的特性,使得接口使用起来更加的得心应手了,这也有助于我们更加内聚自己的代码结构了。Java源码中也有很多场景使用到了默认方法,例如:Iterator接口,我们在开发中可以多使用一些新的特性从而提高开发效率及增加代码的健壮性。


public interface Iterable<T> {

Iterator<T> iterator();

default void forEach(Consumer<? super T> action) {
 Objects.requireNonNull(action);
 for (T t : this) {
  action.accept(t);
 }
}

default Spliterator<T> spliterator() {
 return Spliterators.spliteratorUnknownSize(iterator(), 0);
}

}

总结

来源:https://www.toutiao.com/i6932637837846135300/

标签:java8,默认方法,新特性
0
投稿

猜你喜欢

  • Java中双大括号初始化的理解与使用

    2023-08-30 08:44:55
  • C#实现如何使用短信平台自动通知用户实例

    2022-04-21 07:51:40
  • SpringBoot集成JmsTemplate(队列模式和主题模式)及xml和JavaConfig配置详解

    2022-01-31 05:29:10
  • Java背包问题求解实例代码

    2023-10-05 06:20:33
  • Android唤醒、解锁屏幕代码实例

    2022-09-03 14:11:51
  • c#数据绑定之删除datatable数据示例

    2022-03-18 03:42:24
  • Android 自定义一套 Dialog通用提示框 (代码库)

    2022-10-08 06:20:31
  • Flutter软键盘的原理浅析

    2023-10-15 11:18:34
  • Maven如何打入依赖中指定的部分jar包

    2023-09-22 02:50:33
  • C#实现字体旋转的方法

    2023-01-19 06:41:40
  • java swing实现QQ账号密码输入框

    2023-01-13 06:26:52
  • C#键盘鼠标钩子实例

    2021-10-18 21:05:24
  • 浅谈android Fragment横竖屏翻转对重新加载的要求

    2023-07-27 21:55:28
  • C语言数据结构之单链表与双链表的增删改查操作实现

    2023-01-24 07:27:35
  • Spring Boot2.3 新特性分层JAR的使用

    2021-08-03 12:55:50
  • Java拦截器Interceptor和过滤器Filte的执行顺序和区别

    2022-06-01 20:37:11
  • 深入了解java内存分配和回收策略

    2023-02-27 15:16:58
  • 详解C++ bitset用法

    2022-10-30 08:57:16
  • C#中的虚函数virtual

    2023-09-07 13:49:53
  • C#由当前日期计算相应的周一和周日的实例代码

    2021-12-02 00:37:09
  • asp之家 软件编程 m.aspxhome.com