Java 8的默认方法:可以做什么和不能做什么?
什么是默认方法
在Java 8发行版中,您可以修改接口以添加新方法,以便该接口与实现该接口的类保持兼容。 如果您要开发一个库,该库将由基辅到纽约的几位程序员使用,那么这非常重要。 在Java 8出现之前,如果您在库中发布了接口,则您不能添加新方法,而不必冒险在接口中实现的某些应用程序会随接口的新版本而中断。
使用Java 8,这种恐惧消失了吗? 没有。
向接口添加默认方法可能会使某些类无法使用。
首先让我们看一下默认方法的要点。
在Java 8中,可以在接口中实现一种方法。 (从Java8开始,静态方法也可以在接口中实现,但这是另一回事。)在接口中实现的方法称为默认方法,用关键字default
表示为修饰符。 当类实现接口时,它可以但不必实现已经在接口中实现的方法。 该类继承默认实现。 这就是为什么当接口实现更改时可能不需要触摸类的原因。
多重继承?
当一个具体的类实现多个(例如两个)接口并且这些接口实现相同的默认方法时,事情就变得复杂起来。 该类将继承哪个默认方法? 答案是否定的。 在这种情况下,该类必须自己实现该方法(直接实现或通过继承更高级别的类)。
当只有一个接口实现默认方法而另一个仅将其声明为抽象方法时,也是如此。 Java 8试图受到约束,并避免“隐式”的事情。 如果在多个接口中声明了这些方法,则不会继承任何默认实现,则将出现编译时错误。
但是,如果您已经编译了类,则不会出现编译时错误。 这样Java 8不一致。 它有其原因,我不想在这里详述或出于各种原因而进入辩论(例如:发布已结束,辩论时间很长,并且从未在此平台上使用)。
- 假设您有两个接口,还有一个实现这两个接口的类。
- 接口之一实现默认方法
m()
。 - 您编译所有接口和类。
- 您更改不包含方法
m()
的接口,以将其声明为抽象方法。 - 仅编译修改后的接口。
- 运行课程。
在这种情况下,该类将运行。 您不能使用修改后的接口再次对其进行编译,但是如果它是使用较旧版本进行编译的:它仍然可以运行。 现在
- 修改具有抽象方法
m()
的接口并创建默认实现。 - 编译修改后的接口。
- 运行类:失败。
当有两个接口为同一方法提供默认实现时,该方法不能在实现类中调用,除非由该类实现(再次:直接或从另一个类继承)。
该类是兼容的。 可以使用新界面加载它。 只要两个接口中都没有默认实现的方法的调用,它甚至可以开始执行。
样例代码
为了演示上述内容,我为类C.java
创建了一个测试目录,并为文件I1.java
和I2.java
的接口创建了三个子目录。 测试的根目录在文件C.java
包含类C
的源代码。 目录base
包含适合执行和编译的接口版本。 I1
包含具有默认实现的方法m()
。 接口I2
目前不包含任何方法。
该类包含一个main方法,因此我们可以在测试中执行它。 它测试是否存在任何命令行参数,因此我们可以轻松地执行该方法,而无需调用方法m()
。
~/github/test$ cat C.java
public class C implements I1, I2 {public static void main(String[] args) {C c = new C();if( args.length == 0 ){c.m();}}
}
~/github/test$ cat base/I1.java
public interface I1 {default void m(){System.out.println("hello interface 1");}
}
~/github/test$ cat base/I2.java
public interface I2 {
}
我们可以使用命令行来编译和运行该类:
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
compatible
目录包含声明方法m()
抽象的接口I2
版本,并且出于技术原因,它包含未I1.java
。
~/github/test$ cat compatible/I2.java public interface I2 {void m();
}
这不能用于编译类C
:
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {^
1 error
该错误信息非常准确。 即使我们具有先前编译中的C.class
,并且即使在compatible
目录中编译接口,我们仍将有两个接口可用于运行该类:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
wrong
的第三个目录包含I2
版本,该版本还定义了方法m()
:
~/github/test$ cat wrong/I2.java
public interface I2 {default void m(){System.out.println("hello interface 2");}
}
我们甚至不应该去编译它。 即使方法是双重定义的,只要不调用该方法,该类仍然可以执行,但是只要我们尝试调用方法m()
,该类就会失败。 这就是我们使用命令行参数的目的:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.mat C.m(C.java)at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$
结论
当您开始将库移至Java 8并修改接口以添加默认实现时,您可能不会遇到问题。 至少这是Java 8库开发人员希望将功能方法添加到集合中的方式。 使用您的库的应用程序仍然依赖没有默认方法的Java 7库。 使用和修改不同的库时,冲突的可能性很小。 如何避免这种情况?
像以前一样设计您的库API。 不要轻易依赖默认方法的可能性。 他们是不得已的选择。 明智地选择名称,以避免与其他接口冲突。 我们将学习如何使用此功能来开发Java编程。
翻译自: https://www.javacodegeeks.com/2014/04/java-8-default-methods-what-can-and-can-not-do.html
Java 8的默认方法:可以做什么和不能做什么?相关推荐
- Java 8:默认方法解析规则
随着Java 8中默认方法的引入,一个类现在可以从多个位置(例如另一个类或接口)继承相同的方法. 在这种情况下,可以使用以下规则来确定选择哪种方法: 类或超类方法声明始终优先于默认方法 否则,将使用具 ...
- 【Java 8】默认方法
本文参考书籍<Java 8实战>,陆明刚.劳佳 译,如有侵权,请联系删除! 默认方法简介 我们知道,实现接口的类必须为接口中定义的所有抽象方法提供一个实现,如果向接口中加入了新的方法,那 ...
- Java 8 (8) 默认方法
传统上,Java程序的接口是将相关方法按照预定组合到一起的方式.实现接口的类必须为接口中定义的方法提供一个实现,或者从父类中集成它的实现.但是,一旦类库的设计者需要更新接口,向接口中加入新的方法时候, ...
- java接口的默认方法,实现类调用接口默认方法
概述 Java8带来了一些全新的特性,包括lambda表达式.函数接口.方法引用.流.可选方法.接口中的静态方法和默认方法. 在本文中,我们将深入讨论为什么java8接口新增了默认方法,如何使用默认方 ...
- Java 8默认方法会破坏你的(用户的)代码
Java 8的默认方法试图尝试更进一步简化Java API.不幸的是,这一最近的语言扩展带来了一系列复杂的规则,但只有少部分Java开发者意识到这一点.这篇文章告诉你为什么引入默认方法会破坏你的(用户 ...
- JAVA移慎_谨慎使用Java8的默认方法
为什么要谨慎使用Java8的默认方法?本文给出了为什么要慎用Java8默认方法的原因,解释的很详细,感兴趣的朋友可以参考一下 默认方法给JVM的指令集增加了一个非常不错的新特性.使用了默认方法之后,如 ...
- java的默认值规则_Java 8:默认方法解析规则
java的默认值规则 随着Java 8中默认方法的引入,一个类现在可以从多个位置(例如另一个类或接口)继承相同的方法. 在这种情况下,可以使用以下规则来确定选择哪种方法: 类或超类方法声明始终优先于默 ...
- 注解默认继承_默认方法和多重继承
注解默认继承 最近卢卡斯JOOQ埃德尔发布和文章有关嵌套类及其使用. 这是一个有趣的话题,他的文章一如既往地有趣并且值得一读. 只有一个简短的声明我无法同意,我们有一个简短的回复链,导致了默认方法,以 ...
- 接口默认方法是什么鬼
接口之所以成为接口,就在于它没有实现,只是声明.但后来一切都变了,Java 里出现了默认方法,C# 也出现了默认方法.接口已经不像传统意义上的接口,其概念开始向抽象类靠近,一个纯抽象的东西,突然出现了 ...
最新文章
- 如果神经网络规模足够大,会产生智能吗?
- javascript:document的属性和方法,title,innerHTML,
- 用策略屏蔽135 139 445 3389端口+网络端口安全防护技
- C#字符串截取,查找某字符下标
- express开发实例
- 甲骨文是否可以要求 Java API 享有版权?这场10年官司怎么结
- @JsonSerialize 与 @JsonDeserialize 使用
- Kubernetes插件部署
- Codeforces #364 DIV2
- [译] JAVA初学者的30个常见问题
- anaconda和python有什么不一样_看着一样的胶带,价格为什么不一样?
- Java Balking模式
- 极客学院30天免费vip
- Python编写杨辉三角形
- 南阳 oj 6174问题
- 职场 | 因特尔(Intel)无线modem系统设计师实习岗位面试总结
- 充电桩(charging station)是什么?
- 粤通院 招聘FPGA工程师
- Sass学习笔记 — 4. 参考手册
- UnicodeEncodeError: 'gbk' codec can't encode character '\xa9' in position 314810: illegal multibyte
热门文章
- 2017蓝桥杯省赛---java---C---2(兴趣小组)
- 文章中文字乱码问题解决办法集合
- count() * ,1,字段 三兄弟
- jenkins安装与配置windows_Windows下Scoop安装、配置与使用
- jsr303 spring_使用Spring和JSR 303进行方法参数验证
- spring http缓存_HTTP缓存与Spring示例
- java事件处理过程分布写_Java 9中的进程处理
- apache pdfbox_Apache PDFBox命令行工具:无需Java编码
- kafka分布式_带有Kafka和ZeroMQ的分布式类星体演员
- 捍卫者usb管理控制系统_捍卫Java