Java 8 新特性:接口的静态方法和默认方法

简介: Java 8 新特性:接口的静态方法和默认方法

Java 8 新特性:接口增强


1.接口增强


Java 8 对接口做了进一步的增强。


a. 在接口中可以添加使用 default 关键字修饰的非抽象方法。即:默认方法(或扩展方法)


b. 接口里可以声明静态方法,并且可以实现。


2.默认方法(或扩展方法)


Java 8 允许给接口添加一个非抽象的方法实现,只需要使用 default 关键字即可,这个特征又叫做扩展方法(也称为默认方法或虚拟扩展方法或防护方法)。在实现该接口时,该默认扩展方法在子类上可以直接使用,它的使用方式类似于抽象类中非抽象成员方法。


Note:扩展方法不能够重写(也称复写或覆盖) Object 中的方法,却可以重载Object 中的方法。


eg:toString、equals、 hashCode 不能在接口中被覆盖,却可以被重载。



默认方法允许我们在接口里添加新的方法,而不会破坏实现这个接口的已有类的兼容性,也就是说不会强迫实现接口的类实现默认方法。


默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,接口可以提供一个默认的方法实现,所有这个接口的实现类都会通过继承得到这个方法(如果有需要也可以重写这个方法)


eg:

interface Defaulable {
    //使用default关键字声明了一个默认方法
     @SuppressLint("NewApi")
     default String myDefalutMethod() {
        return "Default implementation";
    }
}
class DefaultableImpl implements Defaulable {
    //DefaultableImpl实现了Defaulable接口,没有对默认方法做任何修改
}
class OverridableImpl implements Defaulable {
        //OverridableImpl实现了Defaulable接口重写接口的默认实现,提供了自己的实现方法。
        @Override
        public String myDefalutMethod() {
            return "Overridden implementation";
        }
}

Note:


JVM平台的接口的默认方法实现是很高效的,并且方法调用的字节码指令支持默认方法。默认方法使已经存在的接口可以修改而不会影响编译的过程。java.util.Collection中添加的额外方法就是最好的例子:stream(), parallelStream(), forEach(), removeIf()


虽然默认方法很强大,但是使用之前一定要仔细考虑是不是真的需要使用默认方法,因为在层级很复杂的情况下很容易引起模糊不清甚至变异错误。




优缺点:


可以在不破坏代码的前提下扩展原有库的功能。但从另一个方面来说,这使得接口作为协议,类作为具体实现的界限开始变得有点模糊。优点是,它通过一个很优雅的方式使得接口变得更智能,同时还避免了代码冗余,并且扩展类库。缺点是,个人估计很快就会看到有在接口方法里获取this引用然后强制转化成某个具体类型的写法了。




多重继承的冲突说明:


由于同一个方法可以从不同接口引入,自然而然的会有冲突的现象,规则如下:


1)一个声明在类里面的方法优先于任何默认方法

2)优先选取最具体的实现


eg:


B重写了A的hello方法:

image.png

输出结果:Hello World from B


小结:


默认方法给予我们修改接口而不破坏原来的实现类的结构提供了便利,目前java 8的集合框架已经大量使用了默认方法来改进了,当我们最终开始使用Java 8的lambdas表达式时,提供给我们一个平滑的过渡体验。也许将来我们会在API设计中看到更多的默认方法的应用。


参考默认方法官方文档地址:


http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html


3.接口的静态方法


接口里可以声明静态方法,并且可以实现。

private interface DefaulableFactory {
   // Interfaces now allow static methods
   static Defaulable create(Supplier< Defaulable > supplier ) {
       return supplier.get();
   }
}

4.接口增强示例


接口的静态方法和默认方法一起调用示例(结合上面的示例,在某类中的main()中演示……)

eg:

public static void main( String[] args ) {
   Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
   System.out.println( defaulable.myDefalutMethod() );
   defaulable = DefaulableFactory.create( OverridableImpl::new );
   System.out.println( defaulable.myDefalutMethod() );
}

输出结果:


Default implementation

Overridden implementation


5.为什么不能用默认方法来重载equals,hashCode和toString?


接口不能提供对Object类的任何方法的默认实现。从接口里不能提供对equals,hashCode或toString的默认实现。因为若可以会很难确定什么时候该调用接口默认的方法。


如果一个类实现了一个方法,那总是优先于默认的实现的。一旦所有接口的实例都是Object的子类,所有接口实例都已经有对equals/hashCode/toString等方法非默认 实现。因此,一个在接口上的这些默认方法都是没用的,它也不会被编译。(简单地讲,每一个java类都是Object的子类,也都继承了它类中的equals/hashCode/toString方法,那么在类的接口上包含这些默认方法是没有意义的,它们也从来不会被编译。)


6.java 8中抽象类与接口的异同


相同点:


1)都是抽象类型;


2)都可以有实现方法(以前接口不行);


3)都可以不需要实现类或者继承者去实现所有方法,(以前不行,现在接口中默认方法不需要实现者实现)


不同点:


1)抽象类不可以多重继承,接口可以(无论是多重类型继承还是多重行为继承);


2)抽象类和接口所反映出的设计理念不同。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系;


3)接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。


Note:friendly 型:如果一个类、类属变量及方法不以public,protected,private这三种修饰符来修饰,它就是friendly类型的,那么包内的任何类都可以访问它,而包外的任何类都不能访问它(包括包外继承了此类的子类),因此,这种类、类属变量及方法对包内的其他类是友好的,开放的,而对包外的其他类是关闭的。



目录
相关文章
|
9天前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
33 17
|
7天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
2天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
8 2
|
5天前
|
Java
Java基础(13)抽象类、接口
本文介绍了Java面向对象编程中的抽象类和接口两个核心概念。抽象类不能被实例化,通常用于定义子类的通用方法和属性;接口则是完全抽象的类,允许声明一组方法但不实现它们。文章通过代码示例详细解析了抽象类和接口的定义及实现,并讨论了它们的区别和使用场景。
|
5天前
|
Java 测试技术 API
Java零基础-接口详解
【10月更文挑战第19天】Java零基础教学篇,手把手实践教学!
15 1
|
4天前
|
Java Spring
JAVA获取重定向地址URL的两种方法
【10月更文挑战第17天】本文介绍了两种在Java中获取HTTP响应头中的Location字段的方法:一种是使用HttpURLConnection,另一种是使用Spring的RestTemplate。通过设置连接超时和禁用自动重定向,确保请求按预期执行。此外,还提供了一个自定义的`NoRedirectSimpleClientHttpRequestFactory`类,用于禁用RestTemplate的自动重定向功能。
|
Java
Java接口和抽象类
Java接口和抽象类
87 0
|
3月前
|
设计模式 Java
【惊天揭秘】Java编程绝技大曝光:接口、抽象类、静态类与非静态类的神秘面纱终被揭开!
【8月更文挑战第22天】Java支持面向对象编程,通过接口、抽象类、静态类(如枚举与工具类)及普通类实现设计原则。接口定义行为规范,允许多重继承;抽象类含未实现的抽象方法,需子类完成;静态类常为工具类,提供静态方法;普通类则实例化对象。恰当运用这些结构能提升程序质量。
39 2
|
6月前
|
设计模式 搜索推荐 Java
java接口和抽象类的区别,以及使用选择
java接口和抽象类的区别,以及使用选择
68 0
|
3月前
|
Java 开发者
Java中的接口和抽象类
Java中的接口和抽象类
28 3