详解Java8的default方法
Java 8新增了default方法,它可以在接口添加新功能特性,而且还不影响接口的实现类。本文是本站小编搜索整理的关于Java8的default方法的详解,有需要的朋友们一起看看吧!想了解更多相关信息请持续关注我们应届毕业生考试网!
什么是default方法?
Java 8发布以后,可以给接口添加新方法,但是,接口仍然可以和它的实现类保持兼容。这非常重要,因为你开发的类库可能正在被多个开发者广泛的使用着。而Java 8之前,在类库中发布了一个接口以后,如果在接口中添加一个新方法,那些实现了这个接口的应用使用新版本的接口就会有崩溃的危险。
有了Java 8,是不是就没有这种危险了?答案是否定的。
给接口添加default方法可能会让某些实现类不可用。
首先,让我们看下default方法的细节。
在Java 8中,接口中的方法可以被实现(Java8中的static的方法也可以在接口中实现,但这是另一个话题)。接口中被实现的方法叫做default方法,用关键字default作为修饰符来标识。当一个类实现一个接口的时候,它可以实现已经在接口中被实现过的方法,但这不是必须的。这个类会继承default方法。这就是为什么当接口发生改变的时候,实现类不需要做改动的原因。
多继承的时候呢?
当一个类实现了多于一个(比如两个)接口,而这些接口又有同样的default方法的时候,事情就变得很复杂了。类继承的是哪一个default方法呢?哪一个也不是!在这种情况下,类要自己(直接或者是继承树上更上层的类)来实现default方法(才可以)。
当一个接口实现了default方法,另一个接口把default方法声明成了abstract的时候,同样如此。Java 8试图避免不明确的东西,保持严谨。如果一个方法在多个接口中都有声明,那么,任何一个default实现都不会被继承,你将会得到一个编译时错误。
但是,如果你已经把你的类编译过了,那就不会出现编译时错误了。在这一点上,Java 8是不一致的。它有它自己的原因,有于各种原因,在这里我不想详细的说明或者是深入的讨论(因为:版本已经发布了,讨论时间太长,这个平台从来没有这样的讨论)。
1.假如你有两个接口,一个实现类。
2.其中一个接口实现了一个default方法m()。
3.把接口和实现类一块编译。
4.修改那个没有包含m()方法的接口,声明m()方法为abstract。
5.单独重新编译修改过的接口。
6.运行实现类。
上面的情况下类可以正常运行。但是,不能用修改过的接口重新编译,但是用老的接口编译仍然可以运行。接下来
1.修改那个含有abstract方法m()的接口,创建一个default实现。
2.编译修改后的接口
3.运行类:失败。
当两个接口给同一个方法都提供了default实现的时候,这个方法是无法被调用的,除非实现类也实现了这个default方法(要么是直接实现,要么是继承树上更上层的类做实现)。
但是,这个类是兼容的。它可以在使用新接口的情况下被载入,甚至可以执行,只要它没有调用在两个接口中都有default实现的方法。
实例代码:
为了演示上面的例子,我给创建了一个测试目录,它下面还有3个子目录,用于存放和。测试目录下包含了类C的源码。base目录包含了可以编译和运行的那个版本的`接口。I1包含了有default实现的m()方法,I2不包含任何方法。
实现类包含了main方法,所以我们可以在测试中执行它。它会检查是否存在命令行参数,这样,我们就可以很方便的执行调用m()和不调用m()的测试。
复制代码 代码如下:
~/github/test$ cat
public class C implements I1, I2 {
public static void main(String[] args) {
C c = new C();
if(th == 0 ){
c.m();
}
}
}
~/github/test$ cat base/
public interface I1 {
default void m(){
tln("hello interface 1");
}
}
~/github/test$ cat base/
public interface I2 {
}
使用下面的命令行来编译运行:
复制代码 代码如下:
~/github/test$ javac -cp .:base
~/github/test$ java -cp .:base C
hello interface 1
compatible目录包含了有abstract方法m()的I2接口,和未修改的I1接口。
复制代码 代码如下:
~/github/test$ cat compatible/
public interface I2 {
void m();
}
这个不能用来编译类C:
复制代码 代码如下:
~/github/test$ javac -cp .:compatible
:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
^
1 error
错误信息非常精确。因为我们有前一次编译获得的s,如果我们编译compatible目录下的接口,我们仍然会得到能运行实现类的两个接口:
复制代码 代码如下:
~/github/test$ javac compatible/I*
~/github/test$ java -cp .:compatible C
hello interface 1
第三个叫做wrong的目录,包含的I2接口也定义了m()方法:
复制代码 代码如下:
~/github/test$ cat wrong/
public interface I2 {
default void m(){
tln("hello interface 2");
}
}
我们应该不厌其烦的编译它。尽管m()方法被定义了两次,但是,实现类仍然可以运行,只要它没有调用那个定义了多次的方法,但是,只要我们调用m()方法,立即就会失败。这是我们使用的命令行参数:
复制代码 代码如下:
~/github/test$ javac wrong/*
~/github/test$ java -cp .:wrong C
Exception in thread "main" mpatibleClassChangeError: Conflicting
default methods: I1.m I2.m
at C.m()
at (:5)
~/github/test$ java -cp .:wrong C x
~/github/test$
结论
当你把给接口添加了default实现的类库移植到Java 8环境下的时候,一般不会有问题。至少Java8类库开发者给集合类添加default方法的时候就是这么想的。使用你类库的应用程序仍然依赖没有default方法的Java7的类库。当使用和修改多个不同的类库的时候,有很小的几率会发生冲突。如何才能避免呢?
像以前那样设计你的类库。可能依赖default方法的时候不要掉以轻心。万不得已不要使用。明智的选择方法名,避免和其它接口产生冲突。
-
Java常用数据结构及类
Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。本文特意为大家收集整理了Java常用数据结构及类,希望大家喜欢!一、Vector类Vector类似于一个数组,但与数组相比在使用上有以下两个优点。1、使用的时候无需声明上限,随着元素的增加,Vec...
-
Java中ArrayList类的使用方法
ArrayList是一个数组队列,相当于动态数组。以下就是小编精心推荐以下就是小编精心推荐的,希望对大家有帮助!,希望对大家有帮助!Java中ArrayList类的用法1、什么是ArrayListArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处:...
-
编写更好的Java单元测试的7个技巧
测试是开发的一个非常重要的方面,可以在很大程度上决定一个应用程序的命运。良好的测试可以在早期捕获导致应用程序崩溃的问题,但较差的测试往往总是导致故障和停机。虽然有三种主要类型的软件测试:单元测试,功能测试和集成测试,但是在这篇博文中,我们将讨论开发人员...
-
如何在Javascript中为String对象添加trim,ltrim,rtrim方法
如何在Javascript中为String对象添加trim,ltrim,rtrim方法呢?下面是小编给大家提供的实现代码,大家可以参考阅读,更多详情请关注应届毕业生考试网。利用Javascript中每个对象(Object)的prototype属性我们可以为Javascript中的内置对象添加我们自己的方法和属性。j...
相关文章
- 2016最新java classloader详解
- Java Callable和Future学习
- A Lifeguard at Johns Beach Saved a Drowning Child,A Lifeguar英语作文
- java中BigDecimal的操作方法详解
- Java8的default方法讲解
- java.util.ArrayDeque类使用方法介绍
- JAVA认证开源技术:关于Java的对象equals方法
- Java中的== 和equals()方法详解与实例教程
- JavaScript中null和undefined的异同
- java的String=a; a==null和a.equals(null)这两个判断有什么区别