Post

[JAVA 8] Default Method

[JAVA 8] Default Method

什么是Default Method

各位如果点开JAVA源码,就会发现List接口竟然有实现了的方法.

List.java

1
2
3
4
5
6
7
default void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final ListIterator<E> li = this.listIterator();
    while (li.hasNext()) {
        li.set(operator.apply(li.next()));
    }
}

它好像拥有所有方法该有的元素,且慢,default是什么鬼?? 鬼说:我就是Default Method

Default Method初衷

众所周知,ArrayList是一个实现了List的一个常用类,那么我们再翻开它的源码看看这里的replaceAll方法是咋了?为啥在List里多了一个replaceAll方法?

ArrayList.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
@SuppressWarnings("unchecked")
public void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final int expectedModCount = modCount;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        elementData[i] = operator.apply((E) elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

Default Method存在的原因是,开发Java API的小伙伴发现了一种通用的方法,能够兼容LinkedList等等等等,包括所有实现了List接口的小伙伴类. 作为你,难道你要把所有实现方法拷贝到每一个接口中去???不!!

引入Default Method,Java就允许用户在给同一个接口下的所有实现方法添加一个默认方法,与此同时又不影响所有现有的实现方法,一举两得,何乐而不为

Default Method思维模式(我是重点)

因为Default Method的特性,将会多大程度上改变你的编码思维呢?

1. 可选方法

你是否有这样的情况 我implements 了一个interface, 却同时需要implement许多不需要用到的实现如Iterator中的remove().

这时候,我们就可以像下面这样写,就不用再实现一个空的方法 如:

Iterator.java

1
2
3
default void remove() {
    throw new UnsupportedOperationException("remove");
}
2. 行为的多继承

什么!多继承!Java不是不允许多继承的咩咩咩!

没错,现在利用default method,你可以实现.

Java不允许多继承,但是允许用户实现多个接口,这样我们就能实现类型多继承.然而由于Java7-的Interface不允许实现方法,我们就无法实现行为多继承,但是今天可以了.

ArrayList.java

1
2
3
4
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
...
}

ArrayList为例,有了行为多继承的思维,我们瞬间就发现了ArrayList不仅仅继承了AbstractList里的那么多行为,还实现了List中的所有default method 定义的行为,包括:replaceAll, sort, spliterator.

有没有很酷!

聪明的小孩回答一定是:没有!

是的,如果我实现了两个接口,有相同的default method怎么办!何乐为同学也有同样的疑问.解答如下.

解决冲突的规则

简单粗暴,直接上代码

例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Ambiguous{
    public static void main(String... args) {
        new C().hello();
        new D().hello();
    }
    interface A {
        default void hello() {
            System.out.println("Hello from A");
        }
    }
    interface B {
        default void hello() {
            System.out.println("Hello from B");
        }
    }
    static class C implements B, A {
        @Override
        public void hello() {
            A.super.hello();//消除歧义,编译器要求提供super类型
        }
    }
    static class D implements B {
    }
}
1
2
Hello from A
Hello from B

如果看不懂,你就可以默默的转行了.

看懂了,继续往下看.

例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class MostSpecific{
    public static void main(String... args) {
        new C().hello();//Hello from B
        new D().hello();//Hello from A
        new E().hello();//Hello from B
        new F().hello();//Hello from F
        new G().hello();//Hello from F
    }
    static interface A{
        public default void hello() {
            System.out.println("Hello from A");
        }
    }
    static interface B extends A{
        public default void hello() {
            System.out.println("Hello from B");
        }
    }
    static class C implements B, A {}
    static class D implements A{}
    static class E extends D implements B, A{}
    static class F implements B, A {
        public void hello() {
            System.out.println("Hello from F");
        }
    }
    static class G extends F implements B, A{}
}

看不懂?请留步.

  • new C().hello(); B为A的子类,更为具体,固调用B.hello()
  • new D().hello(); D继承与A,并且自己没有hello()实现类,固调用A.hello()
  • new E().hello(); E虽然继承与D,但D没有实现类(比较G().hello()),固调用B.hello()
  • new F().hello(); 自己有实现类,优先级最高
  • new G().hello(); 父类F有实现类,直接调用F.hello()

例3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Diamond{
    public static void main(String...args){
        new D().hello();
    }
    static interface A{
        public default void hello(){
            System.out.println("Hello from A");
        }
    }
    static interface B extends A { }
    static interface C extends A {
    }
    static class D implements B, C {
    }
}
1
Hello from A

#完

This post is licensed under CC BY 4.0 by the author.