誰がインターフェースを拡張しますか?なぜ?


20

知る限り、私のクラスのextends親クラスとimplementsインターフェース。しかし、私はを使用できない状況に出くわしますimplements SomeInterface。これは、ジェネリック型の宣言です。例えば:

public interface CallsForGrow {...}

public class GrowingArrayList <T implements CallsForGrow>  // BAD, won't work!
                              extends ArrayList<T> 

ここでの使用implementsは構文的に禁止されています。最初に、<>内でインターフェイスを使用することはまったく禁止されていると考えましたが、そうではありません。可能ですが、extends代わりに使用するだけ ですimplements。その結果、インターフェイスを「拡張」しています。この別の例は動作します:

public interface CallsForGrow {...}

public class GrowingArrayList <T extends CallsForGrow>  // this works!
                              extends ArrayList<T> 

私にはそれは構文上の矛盾と思われます。しかし、Java 6の細かい部分を理解していないのかもしれません。インターフェイスを拡張する必要がある他の場所はありますか?私が拡張するつもりのインターフェースには、いくつかの特別な機能が必要ですか?

回答:


25

ジェネリック型変数の場合、コンパイラTは、クラス、インターフェイス、列挙型、または注釈であるかどうかを実際に気にしません。それが気にするのは、サブタイプとスーパータイプの特定のセットを持つタイプであるということです。

また、他の場所(実際にインターフェイスを実装する場所)でクラスとインターフェイスの区別が関係しているという理由だけで構文を複雑にする理由はありません(たとえばimplement、インターフェイスの場合、定義するすべてのメソッドを実装する必要がありますが、extend(抽象ではない)クラスの場合は必要ありません)。

implementsここで記述する必要があると仮定すると、enum値(単純に記述するのではなく<E extends Enum<E>>)と注釈(簡単に宣言できる)の別個の構文も必要になります<A extends Annotation>

記述する必要がある唯一の場所implementsは、実際にインターフェイスを実装するポイントです。で、そのあなたがインターフェイスで定義されたメソッドを実装する必要がありますので、ポイント(とのみ、そのポイント)の違いは、重要です。他のすべての人にとって、与えられたものAが基本クラスであるか、実装されたインターフェースであるかは問題ではありませんB。それはスーパータイプであり、それだけが重要です。

またextends、インターフェイスで使用する場所がもう1つあることに注意してください。

interface A {
}

interface B extends A {
}

実装していないimplementsため、この時点では間違っB ています A


ロジックを使用する場合は、ジェネリックだけでなく、常に「SendInterfaceの拡張」を使用する必要があります。
ガンヌス

2
@Gangnus:なし、のためので、実装者の間で具体的な差があるextendsimplements、純粋な型システムの観点から問題を見たときに、それは違いがないことを、ただのです。
ヨアヒムザウアー

1
申し訳ありませんが、あなたの考えがわかりません。--1。あるケースでは「純粋な型システムの観点」を使用し、別のケースでは使用しないのはなぜですか?--2。これらの異なる場所で構文の要求が変わるのはなぜですか?説明してください。答えは、可能であれば。
ガンヌス

1
@Gangnus:それTはクラスだと誰が言いますか?Tインターフェイスタイプまたはタイプを参照できますenum
ヨアヒムザウアー

1
C#から来て、この議論全体はばかげています。型のスーパータイプをで示し:ます。そして、内部では、インターフェースは、abstract多重継承を可能にするために、未実装の仮想()メンバーのみを含むという制約を持つ抽象クラスであり、これまで常に使用されてきました。との間に文字通り違いはimplementsありませんextends。両方を同じ単語(extends)または任意の記号(:)に置き換えることができ、何も失われません。
サラ

5

Java 5、特にジェネリックが最初に関心を登録した開発者に利用可能になったとき、構文はまったく異なっていました。の代わりにSet<? extends Foo>Set<? super Bar>Set<+Foo>ありましたSet<-Foo>。しかし、フィードバックは、より具体的であるか、より広い(より多くのクラス)を+意味するかが明確ではないということでした。Sunは、構文を変更することでそのフィードバックに対応しましたが、新しいキーワードを導入しないという制約の範囲内であり、これは後方互換性の問題でした。

その結果、どちらもまったく自然ではありません。あなたが観察すると、extends他の文脈で使用される言語ではないインタフェースを、「拡張」クラスの話に過負荷になっています。そしてsuper、「スーパークラスである」ことを意味するようにオーバーロードされます。これは、キーワードによって以前に表現された関係、つまりスーパークラスを参照する関係の反対方向です。

ただし、インターフェイスの基本はこの変更の影響を受けず、新しい方法で拡張された特別なインターフェイスは導入されません。


+1。同意します。しかし、ヨアヒム・ザウアーは、Tが必然的にクラスであるという誤った考えを見つけました。だから、答えは彼です。あなたの理解は1つ(または2)階上です:-)。私の問題はもっと原始的でした。とにかく私の開発に感謝します。
ガンヌス

2

両方が可能とな構文を禁止する、とのそれらで欠点がある可能がはるかに大きいです。

考えてみてください。

インターフェイスと実装の分離は、プログラミングの基本的なイディオムの1つです。そのため、「インターフェイスは何かを実装する」というスペルを許可する構文は、オペランドの乗算を示すためにプラス記号を使用するものと同じくらい悪いでしょう。


OK。だから、私は本当に何かを理解していません。私はそれを非常に可能性があると考えました。しかし、あなたは問題をまったく説明していません、ごめんなさい。Tはクラスの表現です。ある場所でT拡張を使用し、別の場所でTを実装するのはなぜですか?
ガンヌス

Tで提供した例の@Gangnusは、必ずしもクラスではない型パラメーター参照しています - ヨアヒムが既に言ったことを参照してください。それのための道具を許可すると、私が言及したのと同じ混乱につながります
-gnat

はい、彼のコメントはすでに見ました。回答を入力すると、回答としてマークされます。お二人に感謝と+1が届くまで。
ガンヌス

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.