2015-10-14 4 views
5

ブックからの質問:過去にはのJava 8 - デフォルトメソッド - レガシーコードの懸念

(前のJava 8)が、あなたはそれがためのインターフェースにメソッドを追加するために悪い形だと言われました既存のコードを破ることになります。今度は、デフォルトの実装を提供していれば、新しいメソッドを追加することは大丈夫だと言われています。

  1. どのように安全ですか? Collectionインターフェイスの新しいstreamメソッドがレガシーコードのコンパイルを失敗させるシナリオを記述します。
  2. バイナリ互換性はどうですか? JARファイルからレガシーコードはまだ実行しますか?」に続くが、私はそれらについて非常にわからないよう

私の答えである。

  1. レガシーコードは、メソッドを提供していない場合にのみ、それは安全です
  2. バイナリ互換性は維持されていると思いますが、古いJARファイルのレガシーコードは引き続き実行されます(同じコードを使用している場合は、同じ名前のstreamを同じ名前で使用します)。しかし、私はすべてのことについて明確な議論がありませんs。

これらの回答を確認したり拒否したり、これらの回答にいくつかの引数、参照、または明快さを追加できますか?

+0

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

+1

バイナリ互換性を維持しながら行うことが、言語にデフォルトメソッドを追加する主な動機でした。既存のメソッドにデフォルトを追加するのはバイナリとソース互換です。デフォルトで新しいメソッドを追加すると、バイナリとソースとの互換性があります(サブクラスでのクラッシュメソッドとのモジュロ相互作用 - 非最終クラスに新しいメソッドを追加するのと同じ互換性を持っています)。 –

+1

バイナリ互換性は保持されますが、 [このシナリオ](http://stackoverflow.com/q/26816650/2711488)のように、JREライブラリの動作と相互作用するときに問題が発生します。メソッドが* compatible *シグネチャを持つかもしれないと考えるかもしれないので、それを意図せずに新しい 'default'メソッドをオーバーライドし始めます... – Holger

答えて

8
  1. Collectionの新しいstream()デフォルトの方法はStream<E>、それは同じシグネチャを持つstream()メソッドが含まれている場合、8レガシーコードはコンパイルに失敗しますJavaでも新しいタイプが、その結果、他の何かを返す返します戻り値のタイプの衝突。

  2. レガシーコードは、再コンパイルされない限り、引き続き実行されます。

まず、1.7で、次のように設定

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

、これはコンパイルし、実行:1.8で今

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

は、我々はMyCollectionにストリーム方式を追加。

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

1.8でMyCollectionのみをコンパイルします。

$ 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の前のカスタム 'List'実装で、Java 8の前に' Collections.sort'に委譲して実装することで、このようなメソッドを作ることができます。今、 'Collections.sort'は、Java-8以前のメソッドが意図せずにオーバーライドする' List.sort'にデリゲートします。コンパイラはこの問題についてあなたに教えません... – Holger

関連する問題