4

Javaは私にこれをさせます:

public static class SomeType<I>{}

private static Map<Class<?>, Object> m = new HashMap<Class<?>, Object>();

public static <X> List<SomeType<X>> getList(Class<X> clazz)
{
     return (List<SomeType<X>>)m.get(clazz);//warning
}

また、これを行うことができます:

public static class SomeType<I>{}

private static Map<Class<?>, List<?>> m = new HashMap<Class<?>, List<?>>();

public static <X> List<SomeType<X>> getList(Class<X> clazz)
{
    return (List<SomeType<X>>)m.get(clazz);//warning
}

しかし、それは私にこれをさせません:

public static class SomeType<I>{}

private static Map<Class<?>, List<SomeType<?>>> m = new HashMap<Class<?>, List<SomeType<?>>>();

public static <X> List<SomeType<X>> getList(Class<X> clazz)
{
    return (List<SomeType<X>>)m.get(clazz);//will not compile
}

次の回避策に頼らない限り:

public static class SomeType<I>{}

private static Map<Class<?>, List<SomeType<?>>> m = new HashMap<Class<?>, List<SomeType<?>>>();

public static <X> List<SomeType<X>> getList(Class<X> clazz)
{
    return (List<SomeType<X>>)(Object)m.get(clazz);//warning
}

そのため、Java は から オブジェクト へA<B<C>>、 からへ、 からA<?>A<B<C>>ではなく、 からA<B<?>>への明示的な変換を可能にしA<B<C>>ます。

何故ですか?

4

4 に答える 4

3

3 番目の例は、最初の JLS 5.5.1 ルールに違反しているようです。

S がクラス型の場合:

T がクラス型の場合、|S| のいずれかです。<: |T|、または |T| <: |S|. そうしないと、コンパイル時エラーが発生します。

さらに、T のスーパータイプ X と S のスーパータイプ Y が存在し、X と Y の両方が明らかに異なるパラメータ化された型 (§4.5) であり、X と Y の消去が同じである場合、コンパイル時エラーが発生します。

確かに、Let Sbe List<SomeType<?>>>and Tbe List<SomeType<X>>. これらSとは、と等しくないTため、明らかに異なるパラメーター化された型です。同時に、それらの消去は同じで、:と.<?><X>ListList

したがって、仕様によると、これはコンパイル時エラーにつながります。

最初に にキャストm.get(...)するとき、Object上記の条件に違反していない:ObjectかつList<SomeType<X>>同じ消去がない、さらに、|List<SomeType<X>>| <: |Object|

PSList<?>ケースに関しては、これも前述のルールに違反していません|List<SomeType<X>>| <: |List<?>|

于 2013-07-16T15:19:27.477 に答える
2

Java は、成功しないことが証明されている型キャストをコンパイルしません(物事が宣言された型であると仮定し、値が でないと仮定しますnull)。型キャストが成功するためには、(理論的には) 両方の型のサブタイプである null 以外の型を持つことが可能でなければなりません。

  • Objectto A<B<C>>: 成功する可能性があります。たとえば、typeA<B<C>>は両方のサブタイプです。

  • A<?>to A<B<C>>: 成功する可能性があります。たとえば、typeA<B<C>>は両方のサブタイプです。

  • A<B<?>>to A<B<C>>: これが成功することはありません。つまり、両方のサブタイプであるタイプは存在できません。

最後の 1 つの理由を確認するには、パラメーター化された型の場合、 はifFoo<A>のサブタイプにすることはできず、とは異なり、どちらもワイルドカードではないことを思い出してください。だから考えてください。そのパラメーターは、ワイルドカードではありません (実際の型であり、、、、またはではありません) 。Foo<B>ABA<B<?>>B<?>?? extends something? super something

したがって、のサブタイプにできる唯一のタイプA<B<?>>は、それ自体とSubclassOfA<B<?>>です。同じことが にも当てはまりA<B<C>>ます。A<B<C>>SubclassOfA<B<C>>

では、両方のサブタイプである型を持つことができないことがわかりますか?

于 2013-07-18T03:13:20.487 に答える
1

タイプセーフではないからです。例:

List<Class<?>> classes = new ArrayList<Class<?>>();
classes.add(String.class);

// This is invalid!
List<Class<Boolean>> casted = (List<Class<Boolean>>) classes;
// We've somehow assigned a Class<String> to a Class<Boolean>!
Class<Boolean> invalid = casted.get(0);

また、Java はObjecttoList<Class<Boolean>>および fromList<?>へのキャストを許可しますがList<Class<Boolean>>、どちらも未チェックの警告を生成します。それらはおそらくタイプセーフである可能性があるため、エラーではありませんが、List<Class<?>>toはタイプセーフでList<Class<Boolean>>はありません。

于 2013-07-16T15:16:16.423 に答える
0

これ

public static <X> List<SomeType<X>> getList(Class<X> clazz)
{
    return (List<SomeType<X>>)m.get(clazz);//will not compile
}

コンパイラは SomeType について何も知らないため、許可されません。

型パラメーターとパラメーター Class を使用してメソッドを作成しましたが、その結果、型Xを格納する List を返すことが期待されます。X から SomeType に渡す方法を指定していません。get expect のマップですが、宣言された型 witch is を返します。SomeTypeXObjectSomeType<?>

この?場合は とあまり変わらないのでX、次のようなことができます。

それを修正するには、戻り値の型で使用する場合は、その X が必要であると言う必要があります。

public static <X extends SomeType<?>> List<? super X> getList(Class<X> clazz)
{
    return  m.get(clazz); //No error, no warring ;-)
}
于 2013-07-16T15:26:26.653 に答える