[効果java]アイテム26|のタイプは使用しないでください


GenericクラスとGenericインタフェース


クラスとインタフェース宣言でタイプパラメータが使用されている場合は、JENICクラスまたはJENICインタフェースと呼ばれます.Listインタフェースは、要素タイプを表すタイプパラメータEを受け入れ、List<E>として表す.
GenericクラスとGenericインタフェースは、総称してGenericタイプと呼ばれます.

ジェニーリックタイプとパラメトリックタイプ


ジェニーリックタイプは一連のパラメータ化タイプを定義した.
まずクラス名またはインタフェース名、次にカッコ内に実際のタイプのパラメータをリストします.List<String>とは、要素タイプがStringのリストのパラメトリックタイプを指す.ここで、Stringは、従来型パラメータEに相当する実際型パラメータである.

ジェニーンリック型とロー型


Genericタイプが定義されている場合、付属のプロトタイプ(rawtype)も一緒に定義されます.
「羅型」とは、ジェニーンリック型でタイプパラメータを全く使用しない場合を指す.List<E>の炉型はListです.
この羅型の動作はジェニーリック型のすべての情報が消去されたようだ.これはJENICを開発前のコードと互換性を持たせるための方法である.

プロトタイプの欠点


異なるタイプのデータを入力してもコンパイルおよび実行されます.
[コレクションの原型]
private final Collection stamps = ...;
...
stamps.add(new Coin(...)); // 실수로 동전을 넣는다.
上記のコードのように、他のタイプをコレクションに入れ、コレクションからコインを取り出すまでエラーは見つかりません.
そのため、エラーが発生し、実行時に長い時間が経ってからエラーが発見される可能性があります.そうすると、原因を提供するコードと実行時に問題が発生するコードが分離され、エラーをキャプチャするためにコード全体を表示する必要があります.
この問題を解決するには、パラメータ化された集合タイプを使用して、タイプの安定性を確保する必要があります.

パラメトリックコレクションタイプ


[パラメトリックコレクションタイプ-タイプの安定性を確保]
private final Collection<Stamp> stamps = ...;
このように宣言すると、コンパイラはstampsセットにstampインスタンスのみを配置すべきであることを認識し、予想通りに動作することを確認します.
異なるタイプのインスタンスを挿入すると、コンパイルエラーが発生し、問題が表示されます.
コンパイラは、アセンブリから要素を取り出したすべての場所に非表示のフォーマットコピーを追加し、絶対に失敗しないようにします.

リストとリスト<オブジェクト>


ロスタイプを使用すると、ジェニーンリックの抱擁の安定性と表現性が失われます.
それでも、JavaのGenericを受け入れる前のコードとの互換性のため、このタイプが保持される.Listのようなタイプは使用できないが、List<Object>のように任意のオブジェクトのパラメトリックタイプを許可することは可能である.
ジェネリックタイプではないListとは異なり、List<Object>はすべてのタイプを許可するという意味をコンパイラに伝えている.

ジェニーンリックサブタイプルール

Listを受信List<String>の方法に渡すことができるが、List<Object>を受信方法に渡すことはできない.
これはジェニーリックのサブタイプルールのためです.List<String>Listのサブタイプであるが、List<Object>Listのサブタイプではない.
その結果,List<Object>などのパラメトリックタイプを用いる場合と異なり,Listなどのタイプを用いるとタイプ安定性が失われることが分かった.
[プロトタイプを使用して実行に失敗しました]
public static void main(String[] args) {
        final List<String> strings = new ArrayList<>();
        unsafeAdd(strings, Integer.valueOf(42));
        String s = strings.get(0);
}

private static void unsafeAdd(final List list, final Integer valueOf) {
        list.add(0);
}
このコードはコンパイルできますが、Unchecked call to 'add(E)' as a member of raw type 'java.util.Listの警告が表示されます.
警告を無視してプログラムを実行するとClassCastExceptionが発生します.
[List <Object>タイプを使用-コンパイル時にエラーをチェック]
public static void main(String[] args) {
        final List<String> strings = new ArrayList<>();
        unsafeAdd(strings, Integer.valueOf(42));
        String s = strings.get(0);
}

private static void unsafeAdd(final List<Object> list, final Integer valueOf) {
        list.add(0);
}
ListList<Object>に変更すると、エラーメッセージが出力され、コンパイルできません.

非限定ワイルドカードタイプ


ジェニーリックタイプを使いたいが、実際のタイプパラメータが何なのか気にしたくない場合は、疑問符(?)を使いましょう.
ジェニーリックタイプSet<E>の非限定ワイルドカードタイプはSet<?>です.<?>は、任意のタイプを収容できる最も一般的なパラメトリックタイプである.
[非限定ワイルドカードタイプ-タイプ安全、ソフト]
static int numElementsInCommon(Set<?> s1, Set<?> s2){...}
lotypeと非限定ワイルドカードタイプの違いは、lotypeには任意の要素を加えることができないため、タイプ不変式を破壊しやすく、非限定ワイルドカードタイプ(null以外)を使用すると任意の要素を加えることができないことです.
他の要素を入れると、エラーメッセージが表示されます.
[コレクションを使用して各タイプを比較]
public class TypeTest {
    public static void main(String[] args) {
        List raw = new ArrayList<>(); 
        List<?> wildCard = new ArrayList<>();
        List<Object> generic = new ArrayList<>();

        raw.add("Hello"); // 로 타입 (오류발생x)
        wildCard.add("Hello"); // 컴파일 오류 발생
        generic.add("Hello"); // <Object> 타입 (오류발생x)
    }
}

羅タイプを使用する必要がある場合


class literalはrotypeを使用するべきです。

List.class, String[].class, int.class
JAvaリストではclass文字でパラメトリックタイプを使用できません.

instanceof演算子を使用する場合はタイプを使用します。

if (o instanceof Set) { // 로 타입
	Set<?> s = (Set<?>) o; // 와일드카드 타입
}
実行時にJENICタイプ情報が消去されるため、instanceof演算子は非限定ワイルドカードタイプ以外のパラメトリックタイプに適用できません.
また、instanceof演算子のrotypeおよび非限定ワイルドカードタイプでの動作は同じである.
上記のコードでは、OタイプがSetであることを確認し、Set<?>に変換する.(プロトタイプSetではありません.)これは、コンパイラの警告が発生しないチェック変換です.

整理する


プロトタイプは互換性のために残されただけです.使用すると、実行中に異常が発生する可能性がありますので、使用しないでください.ただし、class literalおよびinstanceof演算子ではrotypeを使用します.