类库
默认方法
Collection
接口中新增了 stream
方法,如果继承它的子类没有实现 stream
方法,就使用它的 stream
方法,这样的方法叫默认方法。
Iterable
接口中也新增了一个默认方法:forEach
,允许用户使用 lambda
表达式作为循环体。
JDK
中 forEach
的实现方法:
1 2 3 4 5
| default void forEach(Consumer<? super T> action) { for (T t : this) { action.accept(t); } }
|
默认方法和子类
Parent
接口定义了默认方法 welcome
,而 ParentImpl
类没有实现 welcome
方法,因此它自然继承了默认方法。
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 29 30 31 32 33
| public class Main { public static void main(String[] args) { Parent parent = new ParentImpl(); parent.welcome(); assert "Parent: Hi!".equals(parent.getLastMessage()); } }
class ParentImpl implements Parent { String body;
@Override public void message(String body) { this.body = body; }
@Override public String getLastMessage() { return this.body; } }
interface Parent { void message(String body);
default void welcome() { message("Parent: Hi!"); }
String getLastMessage(); }
|
新增一个 Child
接口,该类继承 Parent
接口,并且重写 Parent
的默认方法:
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 29 30 31 32 33 34 35 36 37 38
| public class Main { public static void main(String[] args) { Child child = new ChildImpl(); child.welcome(); assert "Child: Hi!".equals(child.getLastMessage()); } }
class ChildImpl implements Child { String body;
@Override public void message(String body) { this.body = body; }
@Override public String getLastMessage() { return this.body; } }
interface Child extends Parent { @Override default void welcome() { message("Child: Hi!"); } }
interface Parent { void message(String body);
default void welcome() { message("Parent: Hi!"); }
String getLastMessage(); }
|
现在,默认方法成了虚方法。
任何时候,一旦子类定义的方法和父类的产生冲突,都会优先选择子类定义的方法:
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 29 30 31 32 33 34 35 36 37 38 39 40
| public class Main { public static void main(String[] args) { Parent parent = new OverridingParent(); parent.welcome(); assert "Override Parent".equals(parent.getLastMessage()); } }
class OverridingParent extends ParentImpl { @Override public void welcome() { message("Override Parent"); } }
class ParentImpl implements Parent { String body;
@Override public void message(String body) { this.body = body; }
@Override public String getLastMessage() { return this.body; } }
interface Parent { void message(String body);
default void welcome() { message("Parent: Hi!"); }
String getLastMessage(); }
|
新增 OverridingChild
类,该类本身并没有任何操作,只是继承 Child
接口和 OverridingParent
类。
但调用的 welcome
方法来自 OverridingParent
类。
原因:与 Child
接口定义的默认方法相比,OverridingParent
类中重写后的 welcome
方法更具体。
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class Main { public static void main(String[] args) { Child child = new OverridingChild(); child.welcome(); assert "Override Parent".equals(child.getLastMessage()); } }
class OverridingChild extends OverridingParent implements Child {
}
class OverridingParent extends ParentImpl { @Override public void welcome() { message("Override Parent"); } }
interface Child extends Parent { @Override default void welcome() { message("Child: Hi!"); } }
class ParentImpl implements Parent { String body;
@Override public void message(String body) { this.body = body; }
@Override public String getLastMessage() { return this.body; } }
interface Parent { void message(String body);
default void welcome() { message("Parent: Hi!"); }
String getLastMessage(); }
|
多重继承
接口允许多重继承,因此有可能遇到 2 个接口包含签名相同的默认方法的情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
class MusicalCarriage implements Carriage, Jukebox {
}
interface Jukebox { default String rock() { return "...all over the world"; } }
interface Carriage { default String rock() { return "...from side to side"; } }
|
解决:可以使用增强的 super
语法,指定使用某个接口的默认方法。
1 2 3 4 5 6
| class MusicalCarriage implements Carriage, Jukebox { @Override public String rock() { return Carriage.super.rock(); } }
|
三定律
如果对多重继承下的默认方法工作原理没有把握,可以参考以下3条:
- 类 > 接口。如果继承链中有方法体或抽象的方法声明,那就可以忽略接口中定义的方法。
- 子类 > 父类。如果一个接口继承了另一个接口,且两个接口都定义了一个默认方法,则子类优先。
- 没有3。如果以上2条不适用,子类要么实现该方法,要么将该方法声明为抽象方法。
Optional
Optional
是核心类库新设计的数据类型,用来替换 null
值。
Optional
对象相当于值的容器,可以使用 get()
获得该值。
创建某个值的 Optional
对象:
1 2
| Optional<String> a = Optional.of("a"); assert "a".equals(a.get());
|
Optional
对象可以为空:
1 2 3 4 5 6 7 8 9 10
| Optional<String> emptyOptional = Optional.empty();
Optional<String> alsoEmpty = Optional.ofNullable(null);
assert emptyOptional.isPresent() == false;
assert alsoEmpty.isPresent() == false;
|
但对象为空时,如果希望使用备选值,可以使用 orElse
。
如果备选值计算太繁琐,可以使用 orElseGet
,该方法接受 Supplier
对象。
1 2 3 4 5 6 7
| Optional<String> emptyOptional = Optional.empty();
Optional<Integer> alsoEmpty = Optional.ofNullable(null);
assert "b".equals(emptyOptional.orElse("b"));
assert 3 == alsoEmpty.orElseGet(() -> 1 + 2);
|