2011-08-14 9 views
9

を経由してコンパイルしていない私は、次の構造を有する:共変戻り値の型があるJavac

FooBar.java:2: types Bar and Foo are incompatible; both define fooBar(), but with unrelated return types 
public interface FooBar extends Foo, Bar { 
    ^
1 error 

しかし、Eclipseは罰金それをコンパイルすることができ、そして限り:

public interface BarReturn {} 
public interface FooReturn {} 
public interface FooBarReturn extends FooReturn, BarReturn {} 

public interface Foo { 
    FooReturn fooBar(); 
} 

public interface Bar { 
    BarReturn fooBar(); 
} 

public interface FooBar extends Foo, Bar { 
    FooBarReturn fooBar(); 
} 

javacは、次のメッセージで失敗しますFooBarのfooBar()メソッドは、共変リターンを使用してFooとBarのfooBar()メソッドの両方の規約を満たしています。

これはEclipseコンパイルまたはjavacのバグですか?あるいはjavacをコンパイルするよう説得する方法はありますか?参考までに私のjavacオプションは次のようになります:

javac -d /tmp/covariant/target/classes -sourcepath /tmp/covariant/src/main/java: /tmp/covariant/src/main/java/Foo.java /tmp/covariant/src/main/java/BarReturn.java /tmp/covariant/src/main/java/FooBarReturn.java /tmp/covariant/src/main/java/Bar.java /tmp/covariant/src/main/java/FooReturn.java /tmp/covariant/src/main/java/FooBar.java -g -nowarn -target 1.6 -source 1.6 
+0

open-jdkコンパイラのバージョン1.6.0_22にも同じ問題があります。それはjava7で動作します。 –

+0

ちょうどそれをテストし、はい、そうです - 素晴らしい。 –

+0

可能[duplicate](http://stackoverflow.com/questions/11343238/java-implementing-multiple-interfaces-with-same-method-and-different-return-ty)? – amaidment

答えて

3

FooとBarの両方をFooBarインターフェイスで拡張しています。そのため、互換性のない戻り型の2つのメソッドを継承しています。 Javaの共分散は、Liskov置換の後にのみ許可されます。別名では、オーバーライド候補タイプは、オーバーライドされた戻りタイプのサブクラスである必要があります。このべきコンパイルのようなもの上記のあなたの例では

public interface BarReturn {} 
public interface FooReturn {} 
public interface FooBarReturn extends FooReturn, BarReturn {} 

public interface Foo { 
    FooReturn fooBar(); 
} 

public interface FooBar extends Foo{ 
    FooBarReturn fooBar(); 
} 
+0

OPのコードでは、オーバーライドされたメソッドの戻り値の型は、オーバーライドされた両方のメソッドの戻り値の型を行います*。したがって、学術的な観点から、OPのコードが有効ではない理由はありません。 –

1

The JLS (§9.4.1)は言う:

インタフェースは オーバーライド-同等のシグネチャを持ついくつかのメソッドを継承することが可能です(§ 8.4.2)。このような状況は、 自体ではコンパイル時エラーが発生しません。インタフェースはすべてのメソッドを継承する とみなされます。ただし、継承されたメソッドの1つは、 は、他の継承されたメソッドの代わりに返される型でなければなりません。 そうでない場合は、コンパイル時エラーが発生(ザ・は節はこのケースではない 原因のエラーを行うスローされます。)

だから私はjavacのが正しいと言うでしょう。しかし、これは私に弁護士の専門用語のように見えるので、私は間違っている可能性があります。

1

このjavaranch discussionの回答は、javacのバグであることを示唆しているようです。しかし、参照番号bug urlは機能していないようです。

+0

[JDK-7u4](http://www.oracle.com)のようです。com/technetwork/java/javase/downloads/jdk-7u4-downloads-1591156.html)はバグを修正します。 – Georg

1

回避策として、あなたは

interface Foo1 extends Foo { 
    FooBarReturn fooBar(); 
} 
interface Bar1 extends Bar { 
    FooBarReturn fooBar(); 
} 
public interface FooBar extends Foo1, Bar1 { } 

きれいではありませんを行うことができますが、トリックを行う必要があります。

+1

おかげさまで、それは良い考えです - しかし、OpenJDK 7のjavacとEclipseコンパイラを使ってコンパイルするので、余分な型を導入することなく回避することができます。 –

+1

これはうまくいかないようですが、jdk6のjavacでは 'Bar1とFoo1の型は互換性がありません。どちらもfooBar()を定義しますが、関連のない戻り値の型を持ちます。 –

1

同じ問題があり、OracleのJDK 7を使用しても問題ないと思われます。