由于Java 8允许在名为Default Methods的接口中默认实现方法,因此在何时使用a之间似乎存在混淆abstract class.
那么什么时候应该使用与默认方法的接口,何时应该使用抽象类?抽象类在这种情况下仍然有用吗?
Java 8最有用的功能之一是default接口上的新方法.基本上有两个原因(可能还有其他原因)为什么会被引入:
Iterator.remove()Iterable.forEach()从API设计者的角度来看,我希望能够在接口方法上使用其他修饰符,例如final.在添加便捷方法时,这将非常有用,可防止在实现类时出现"意外"覆盖:
interface Sender {
// Convenience method to send an empty message
default final void send() {
send(null);
}
// Implementations should only implement this method
void send(String message);
}
Run Code Online (Sandbox Code Playgroud)
如果Sender是一个类,上面已经是常见的做法:
abstract class Sender {
// Convenience method to send an empty message
final void send() {
send(null);
}
// Implementations should only implement this method
abstract void send(String message);
}
Run Code Online (Sandbox Code Playgroud)
现在,default并final有明显矛盾的关键字,但默认关键字本身不会一直严格要求 …
Java 8引入了默认方法,以提供扩展接口的能力,而无需修改现有实现.
我想知道,当该方法被覆盖或由于不同接口中的冲突默认实现不可用时,是否可以显式调用方法的默认实现.
interface A {
default void foo() {
System.out.println("A.foo");
}
}
class B implements A {
@Override
public void foo() {
System.out.println("B.foo");
}
public void afoo() {
// how to invoke A.foo() here?
}
}
Run Code Online (Sandbox Code Playgroud)
考虑到上面的代码,你会如何A.foo()从B类方法调用?
在Java 8中,我可以轻松地写:
interface Interface1 {
default void method1() {
synchronized (this) {
// Something
}
}
static void method2() {
synchronized (Interface1.class) {
// Something
}
}
}
Run Code Online (Sandbox Code Playgroud)
我将获得完全同步语义,我也可以在类中使用.但是,我不能synchronized在方法声明上使用修饰符:
interface Interface2 {
default synchronized void method1() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
static synchronized void method2() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我们可以认为,这两个接口的行为方式相同,只是Interface2建立了一个合同上的method1()和method2(),这是比强一点Interface1呢.当然,我们也可能会争辩说default实现不应该对具体实现状态做出任何假设,或者这样的关键字根本不会减轻它的重量.
JSR-335专家组决定不支持synchronized接口方法的原因是什么?
默认方法是我们的Java工具箱中一个不错的新工具.但是,我尝试编写一个定义default该toString方法版本的接口.Java告诉我这是禁止的,因为声明的方法java.lang.Object可能不会被default编辑.为什么会这样?
我知道存在"基类永远胜利"规则,因此默认情况下(pun;),方法的任何default实现Object都会被方法覆盖Object.但是,我认为没有理由说明Object规范中的方法不应该有例外.特别是对于toString具有默认实现可能非常有用.
那么,Java设计者决定不允许default方法覆盖方法的原因是什么Object?
在Java 8中使用默认方法作为穷人的特征是一种安全的做法吗?
一些人声称如果你只是为了它而使用它们可能会让熊猫感到悲伤,因为它很酷,但这不是我的意图.还经常提醒的是,引入了默认方法来支持API演变和向后兼容性,这是事实,但这并不会使它们错误或扭曲以将它们用作特征本身.
我有以下实际用例:
public interface Loggable {
default Logger logger() {
return LoggerFactory.getLogger(this.getClass());
}
}
Run Code Online (Sandbox Code Playgroud)
或许,定义一个PeriodTrait:
public interface PeriodeTrait {
Date getStartDate();
Date getEndDate();
default isValid(Date atDate) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
无可否认,可以使用组合(甚至是辅助类),但它看起来更冗长,更混乱,并且不允许从多态性中受益.
那么,使用默认方法作为基本特征是否可行/安全,还是应该担心不可预见的副作用?
关于SO的几个问题与Java vs Scala特征有关; 这不是重点.我也不仅仅是在征求意见.相反,我正在寻找一个权威的答案或至少是现场洞察力:如果你在公司项目中使用默认方法作为特征,那么它是否真的是一个时间炸弹?
在初始化类之前,必须初始化其直接超类,但不会初始化类实现的接口.同样,在初始化接口之前,不会初始化接口的超接口.
为了我自己的好奇心,我尝试了它,正如预期的那样,界面InterfaceType没有被初始化.
public class Example {
public static void main(String[] args) throws Exception {
InterfaceType foo = new InterfaceTypeImpl();
foo.method();
}
}
class InterfaceTypeImpl implements InterfaceType {
@Override
public void method() {
System.out.println("implemented method");
}
}
class ClassInitializer {
static {
System.out.println("static initializer");
}
}
interface InterfaceType {
public static final ClassInitializer init = new ClassInitializer();
public void method();
}
Run Code Online (Sandbox Code Playgroud)
这个程序打印
implemented method
Run Code Online (Sandbox Code Playgroud)
但是,如果接口声明了default方法,则会发生初始化.考虑InterfaceType给出的接口为
interface InterfaceType {
public …Run Code Online (Sandbox Code Playgroud) 通常情况下,Java源代码已向前兼容.在Java 8之前,据我所知,编译类和源代码都已经与后来的JDK/JVM版本向前兼容.[更新:这是不正确的,请参阅下面的注释'en en'等.]但是,在Java 8中添加了默认方法后,似乎不再是这种情况.
例如,我一直使用的库的实现java.util.List包括一个List<V> sort().此方法返回已排序的列表内容的副本.这个库作为jar文件依赖项部署,在使用JDK 1.8构建的项目中运行良好.
但是,后来我有机会使用JDK 1.8重新编译库本身,我发现库不再编译: - List使用自己的sort()方法实现的类现在与Java 8 java.util.List.sort()默认方法冲突.Java 8 sort()默认方法对列表进行排序(返回void); 我的库的sort()方法 - 因为它返回一个新的排序列表 - 具有不兼容的签名.
所以我的基本问题是:
也:
以下是在1.7下编译和运行并在1.8下运行的一些代码示例 - 但不在1.8下编译:
import java.util.*;
public final class Sort8 {
public static void main(String[] args) {
SortableList<String> l = new SortableList<String>(Arrays.asList(args));
System.out.println("unsorted: "+l);
SortableList<String> s = l.sort(Collections.reverseOrder());
System.out.println("sorted : "+s);
}
public static class SortableList<V> extends ArrayList<V> { …Run Code Online (Sandbox Code Playgroud) Java 8包含了一个名为Defender方法的新功能,它允许在接口中创建默认方法实现.
首先,对于Java中所有精简程序员来说,这是一个巨大的范式转换.我查看了Brain Goetz给出的JavaOne 13演示文稿,他正在讨论集合库中的新内容stream()和parallelStream()实现.
为了在Collection界面中添加新方法,他们不能在不破坏以前版本的情况下添加新方法.所以他说,为了迎合这一点,我们增加了Default方法的新功能.
public interface SimpleInterface {
public void doSomeWork();
//A default method in the interface created using "default" keyword
default public void doSomeOtherWork(){
System.out.println("DoSomeOtherWork implementation in the interface");
}
}
Run Code Online (Sandbox Code Playgroud)
现在我的问题基本上是默认方法只是在需要向接口添加新方法而不破坏客户端代码时才有用吗?或者它也有一些其他用途吗?
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Run Code Online (Sandbox Code Playgroud)
然后说
无法从lambda表达式中访问默认方法.以下代码无法编译:
Formula formula = (a) -> sqrt( a * 100);
Run Code Online (Sandbox Code Playgroud)
但他没有解释为什么不可能.我运行了代码,它给出了一个错误,
不兼容的类型:公式不是功能接口`
那么为什么不可能或错误的含义是什么?该接口满足具有一种抽象方法的功能接口的要求.
default-method ×10
java ×10
java-8 ×10
interface ×5
jsr335 ×2
inheritance ×1
lambda ×1
synchronized ×1
traits ×1