このコードがコンパイルされる理由
final ArrayList<?> dp1 = new ArrayList<String>();
しかし、これはそうではありません
final ArrayList<ArrayList<?>> dp2 = new ArrayList<ArrayList<String>>();
理解するのは非常に複雑ですが、要約すると、最初のコードはString拡張されます?が、2 番目のコードはコンパイルされArrayList<String>ません。2 番目の例をコンパイルする場合は、次のように変更する必要があります。ArrayList<?>
final ArrayList<? extends ArrayList<?>> dp2 = new ArrayList<ArrayList<String>>();
の
final ArrayList<?> dp1 = new ArrayList<String>();
type 引数?は、 のスーパーセット (スーパータイプではない) であるワイルドカードですString。で、ArrayList<?>のスーパータイプですArrayList<String>。
しかし、
final ArrayList<ArrayList<?>> dp2 = new ArrayList<ArrayList<String>>();
型引数ArrayList<?>(?未知の型を表すだけで、 とは何の関係もないパラメータ化された型String) はワイルドカードではありません。ワイルドカードは であり? extends ArrayList<?>、ArrayList<?>実際には のスーパータイプですArrayList<String>。
パラメータ化された型のスーパー/サブ セット/型に関する規則については、こちらを参照してください。