web-dev-qa-db-ja.com

ジェネリッククラスの拡張

public class MyGeneric<T, E> {}

public class Extend1<T, E> extends MyGeneric<T, E> {}

public class Extend2 extends MyGeneric<String, Object> {}

私の知る限り、上記の例のサブクラスは両方とも有効です。 Javaは、サブクラスがインスタンス化されるときにスーパークラスで指定された型がいつ定義され、実際のクラス名であるかをどのように知るのか(つまり、T、Eクラス名ではない)?

補足説明として、ジェネリック型に複数の文字を使用することは(たとえ一般的ではないにしても)許されますか? (計画の重大なエラーにより)型が既存のクラスと競合する場合.

public class E{}
public class Foo<E>{}

それではどうなりますか?

編集:すぐに答えてくれてありがとう。最初の質問に答えるには、 Joachimの答え が最も効果的です。

サイドポイントに答えるために、 aioobeの答えはより明確です

52
James

この定義を見てみましょう:

public class Extend1<T, E> extends MyGeneric<T, E> {}

ここで、TEはそれぞれ2回、2つの異なる役割で存在します

  • Extend1<T,E> youdefine型引数。これは、タイプExtend1には、2つの(無制限の)型引数TおよびEがあります。 これは、Javaコンパイラに、useExtend1タイプを指定する必要があります。
  • extends MyGeneric<T,E> youuse以前に定義された型引数を使用します。ここでTEが型引数として知られていない場合、TEは単純な型参照になります。つまり、コンパイラはクラスを探します(またはインターフェイス、...)という名前のTおよびE(ほとんどの場合、それらは見つかりません)。

はい、型引数はJavaの他の識別子と同じ構文規則に従うため、複数の文字ABCを使用することも、混乱を招く名前を使用することもできます(Stringという型引数を使用することは、しかし、非常に紛らわしい)。

単一文字型の引数名は、非常に一般的な命名戦略です。

58
Joachim Sauer

サブクラスがインスタンス化されるとき、および実際のクラスであるときに、スーパークラスで指定された型がいつ定義されるかをJavaがどのように知るのか疑問に思っていました名前(つまり、T、Eがクラス名ではないことをどのように知っていますか?)

Javaは気にしません。もしあなたがそうするなら...

class MyGeneric<String> extends ArrayList<String> {
    String value;
}

ジェネリック型に複数の文字を使用することは(たとえ珍しいとしても)許容されますか? (計画の重大なエラーにより)型が既存のクラスと競合する場合(例:

はい、型パラメーターには任意の有効なJava識別子を使用できます。

名前は競合する可能性がありますが、Javaはこれをエラーとして扱いません。 <...>間の識別子は、識別子がクラス名に対応するかどうかに関係なく、常に型パラメーターとして扱われます。

しかし、かなり混乱するかもしれません。次に例を示します。

class MyGeneric<String> extends Java.util.ArrayList<String> {
    String value;
}

class Test {
    public static void main(String... args) throws Exception {
        MyGeneric<Integer> obj = new MyGeneric<Integer>();
        obj.value = 5;
        //          ^
        //          |
        //          '--- Assign an integer to what seems to be a String!
    }
}

同様の質問:

22
aioobe

問題ありません:

public class E{}
public class Foo<E>{}

Foo<E>のコンテキストでは、Eは型であるためです。

2
Bohemian