Java 8 - 默认方法 - 对遗留代码的关注

pet*_*rov 5 java java-8 default-method

一本书的问题:

在过去(Java 8之前版本),您被告知将方法添加到接口是一种糟糕的形式,因为它会破坏现有代码.现在您被告知可以添加新方法,前提是您还提供默认实现.

  1. 这有多安全?描述接口的新stream方法Collection导致遗留代码编译失败的情况.
  2. 二进制兼容性怎么样?来自JAR文件的遗留代码是否仍会运行?"

我的答案如下,但我不太确定.

  1. 仅当遗留代码不提供具有相同名称stream和相同签名的方法时(例如,在实现的遗留类中Collection),它才是安全的.否则,这个旧的遗留代码将无法编译.
  2. 我认为保留了二进制兼容性,旧JAR文件中的遗留代码仍将运行.但我对此没有明确的论据.

任何人都可以确认或拒绝这些答案,或者只是为这些答案添加更多参数,参考或清晰度吗?

rge*_*man 8

  1. 新的stream()默认方法Collection返回a Stream<E>,也是Java 8中的新类型.如果遗留代码包含stream()具有相同签名的方法,但返回其他内容,则会导致返回类型的冲突,因此遗留代码将无法编译.

  2. 只要没有重新编译,旧版代码就会继续运行.

首先,在1.7中,设置以下内容:

public interface MyCollection {
    public void foo();
}

public class Legacy implements MyCollection {
    @Override
    public void foo() {
        System.out.println("foo");
    }

    public void stream() {
        System.out.println("Legacy");
    }
}

public class Main {
    public static void main(String args[]) {
        Legacy l = new Legacy();
        l.foo();
        l.stream();
    }
}
Run Code Online (Sandbox Code Playgroud)

-source 1.7 -target 1.7,编译并运行:

$ javac -target 1.7 -source 1.7 Legacy.java MyCollection.java Main.java
$ java Main
foo
Legacy
Run Code Online (Sandbox Code Playgroud)

现在在1.8中,我们将stream方法添加到MyCollection.

public interface MyCollection
{
    public void foo();
    public default Stream<String> stream() {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们只MyCollection在1.8 编译.

$ javac MyCollection.java
$ java Main
foo
Legacy
Run Code Online (Sandbox Code Playgroud)

当然我们不能再重新编译Legacy.java了.

$ javac Legacy.java
Legacy.java:11: error: stream() in Legacy cannot implement stream() in MyCollection
    public void stream()
                ^
  return type void is not compatible with Stream<String>
1 error
Run Code Online (Sandbox Code Playgroud)

  • 请注意,使用默认方法时,此兼容性角落不是新的; 如果将方法添加到与某些子类中的同名方法不兼容的超类,则Java 1.0中也存在同样的问题.向具有默认值的接口添加方法具有与向类添加方法完全相同的兼容性特征. (5认同)
  • 我认为,碰撞方法是一个较小的问题,因为编译器会发现它们.签名不冲突时会出现更大的问题.使用`stream()`,它是不可能的,因为返回类型是一个新类.但想想`sort(Comparator)`.你可以在Java 8之前的自定义`List`实现中使用这样的方法,在Java 8之前,通过委托给`Collections.sort`实现它是合理的.现在,`Collections.sort`委托给`List.sort`,这是Java 8之前的方法无意中覆盖的.编译器不会告诉你这个问题...... (3认同)