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不通的标识:
在多继承中使用默认方法问题
如果两个或多个接口具有相同的默认方法签名,并且一个类实现了这两个接口,则将引发编译时错误。例如:
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/


猜你喜欢
- 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供
- 本文实例为大家分享了Java实现简单幸运抽奖的具体代码,供大家参考,具体内容如下代码模块:User类:package test1;publi
- /// <summary> /// 汉字转拼音缩写 /// </summary> /// <param nam
- 简介网上对于 Camera2 的介绍有很多,在 Github 上也有很多关于 Camera2 的封装库,但是对于那些库,封装性太强,有时候我
- /** * 冒泡排序估计是每本算法书籍都会提到的排序方法。 * 它的基本思路是对长度为N的序列,用N趟来将其排成有序序列。 * 第1趟
- 同步是一种只允许一个线程在特定时间访问某些资源的技术。没有其他线程可以中断,直到所分配的线程或当前访问线程访问数据完成其任务。在多线程程序中
- 首先添加一个timer,50susing System;using System.Collections.Generic;using Sys
- 本文实例讲述了Android播放assets文件里视频文件相关问题。分享给大家供大家参考,具体如下:今天做了一个功能,就是播放项目工程里面的
- 本文实例为大家分享了java顺时针打印矩阵的具体代码,供大家参考,具体内容如下github:剑指offer编程题 import j
- protobuf对象不能直接使用jsonlib去转,因为protobuf生成的对象的get方法返回的类型有byte[],而只有String类
- Java的在还没有发现新写法之前时,我一直是这么初始化List跟Map://初始化List List&l
- 实例如下所示:private static String savefile = "E:\\test.txt";priva
- 一、常规形式1 项目结构2 配置文件及环境设置(1)配置文件# 应用服务 WEB 访问端口server.port=8080# spring
- 一 关键pom<dependencies> <dependency> <groupId>or
- 谨记:Url表只储存受保护的资源,不在表里的资源说明不受保护,任何人都可以访问1、MyFilterInvocationSecurityMet
- 多进程如果需要的时候,app可以创建多进程。在进程里面各类组件元素的清单文件条目 、 、 和— 均支持 android:process 属性
- 实现备份短信到xml文件和像短信中插入一条数据一、实现短信将备份到xml文件中在布局文件中定义一个按钮,定义点击事件为copyClickMa
- C# 复制与删除文件的实现方法1、首先是复制文件首先打开我们的对话框获得文件路径,当然也可以直接编写路径private void BtnAd
- 本文实例讲述了C#实现身份证号码验证的方法。分享给大家供大家参考。具体实现方法如下:随着现在互联网的发展,越来越多的注册用户的地方都用到了身
- 1,通过Handler机制主线程中定义Handler,子线程发消息,通知Handler完成UI更新,Handler对象必须定义在主线程中,如