2015-10-14 46 views
5

从一本书问:的Java 8 - 默认的方法 - 关注遗留代码

在过去(前的Java 8),你被告知,这是不礼貌的方法添加到界面,因为它会破坏现有的代码。现在您被告知可以添加新方法,前提是您还提供了默认实现。

  1. 安全性如何呢?描述一个场景的Collection接口的新stream方法导致的遗留代码失败编译。
  2. 什么二进制兼容性?从一个JAR文件遗留代码仍然可以运行?”

我的答复如下,但我不能肯定他们。

  1. 它的安全只有遗留代码不提供一种方法同名stream并具有相同的签名(例如,在遗留类中实现Collection)否则,这个旧的遗留代码将无法编译
  2. 我认为二进制兼容性被保留,旧的JAR文件的遗留代码仍将运行但我根本没有明确的论点秒。

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

+0

[相关](http://stackoverflow.com/a/22618640/335858)。 – dasblinkenlight

+1

这样做,同时保持二进制兼容性是添加默认的方法对语言的主要动机。将缺省值添加到现有方法是二进制和源兼容的;添加一个默认的新方法是二进制和源兼容的(与子类中的冲突方法进行模数交换 - 这与向非最终类添加新方法具有相同的兼容性特性。) –

+1

尽管保留了二进制兼容性,但仍可能当它与JRE库行为进行交互时会出现问题,如[本场景](http://stackoverflow.com/q/26816650/2711488)中所述。你也可以考虑一个方法可能有一个* compatible *签名,因此,开始覆盖一个新的'default'方法而不打算它... – Holger

回答

8
  1. Collectionstream()默认方法返回一个Stream<E>,也是一个新的类型在Java中,如果它包含一个stream()方法具有相同签名8.遗留代码将无法编译,但没有别的东西返回,导致返回类型的冲突。

  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(); 
    } 
} 

随着-source 1.7 -target 1.7,这编译和运行:

$ javac -target 1.7 -source 1.7 Legacy.java MyCollection.java Main.java 
$ java Main 
foo 
Legacy 

现在,在1.8中,我们添加了流方法MyCollection

public interface MyCollection 
{ 
    public void foo(); 
    public default Stream<String> stream() { 
     return null; 
    } 
} 

我们只编译MyCollection 1.8。

$ javac MyCollection.java 
$ java Main 
foo 
Legacy 

当然我们不能重新编译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 
+5

请注意,这个兼容的角落案例对于默认方法来说并不新鲜。如果您将某个方法添加到与某些子类中的同名命名方法不兼容的超类中,则Java 1.0也存在同样的问题。向缺省接口添加方法与向类中添加方法具有完全相同的兼容性特性。 –

+3

我认为,碰撞方法是编译器发现的小问题。当签名不冲突时会出现更大的问题。使用'stream()',这是不可能的,因为返回类型是一个新类。但想想'sort(Comparator)'。在Java 8之前,在Java 8之前,您可以在自定义的'List'实现中使用这种方法,通过委托给'Collections.sort'实现它是合理的。现在,'Collections.sort'委托给'List.sort',这是Java 8之前的方法无意的覆盖。编译器不会告诉你这个问题... – Holger