回転:JAVA 5汎用型の新特性

6566 ワード

Java5.0の新しい特性の1つは,汎用型と汎用型法を導入することである.1つの汎用タイプは、1つ以上のタイプ変数を使用して定義され、1つ以上のタイプ変数をパラメータまたは戻り値として使用するプレースホルダを有します.たとえば、タイプjava.util.Listは、プレースホルダEによって要素のタイプが記述されるlistの汎用タイプである.このタイプにはadd()というメソッドがあり、Eタイプのパラメータがあると宣言され、get()メソッドがあり、戻り値がEタイプと宣言されます.汎用タイプを使用するには、タイプ変数の実際のタイプを詳細に指定し、Listのようなパラメータ化タイプを形成する必要があります.[1]これらの追加のタイプ情報を示す理由は、コンパイラがコンパイル中に強力なタイプチェックを提供し、プログラムのタイプセキュリティを強化できるためです.たとえば、Stringオブジェクトしか保持できないリストがある場合、このタイプのチェックでString[]オブジェクトの追加を阻止できます.同様に、追加されたタイプ情報により、コンパイラはいくつかのタイプ変換を行うことができます.たとえば、コンパイラはListにStringオブジェクトであるget()メソッドがあることを知っています.そのため、戻り値をObjectからStringに強制的に変換する必要はありません.  Java.utilパッケージの集合クラスはjava 5にあります.0ではすでに汎用化されており、プログラムで頻繁に使用されるかもしれません.タイプセキュリティの集合クラスは、汎用タイプの典型的なケースです.独自の汎用タイプを定義したことがなくてもjava以外は使用したことがありません.utilの中の集合クラス以外の汎用タイプでは,タイプの安全な集合クラスの利点も極めて有意義なシンボルである--彼らはこの主要な新しい言語特性の複雑さを証明した.タイプ安全の集合クラスにおける基本的な汎用用法の探索から始め,さらに汎用タイプをより多く使用する複雑な詳細を検討した.次に,タイプパラメータワイルドカードと境界ワイルドカードについて議論する.汎用型をどのように使用するかを描いた後,独自の汎用型と汎用型の方法をどのように記述するかを明らかにした.汎用型についての議論は、JavaAPIのコアにおいて重要な汎用型の旅行に終わります.この旅はこれらのタイプと彼らの使い方を探求し、共通型がどのように働いているかという問題を深く理解することを目的としています.タイプセキュリティ集合クラスJava.utilクラスパッケージには、Java Collections Framework(Java Collections Framework)が含まれています.これは、オブジェクトのset、オブジェクトのlist、key-FONT color=#0000 ff>valueを含むmapのセットです.第5章では集合クラスについて述べる.ここではjava 5について議論します.0のコレクションクラスでは、タイプパラメータを使用して、コレクション内のオブジェクトのタイプを定義します.この議論はjava 1には向いていない.4以降.汎用型がない場合は、集合クラスの使用には、プログラマが各集合の要素のタイプを記憶する必要があります.java 1にいるとき4種類のコレクションが作成され、コレクションに挿入するオブジェクトのタイプはわかりますが、コンパイラは知りません.適切なタイプの要素を注意深く追加する必要があります.コレクションから要素を取得する必要がある場合は、Objectから本当にタイプに変換するために、明示的にタイプ変換を強制する必要があります.下のjava 1を考察する.4のコードです.
public static void main(String[] args) {
    // This list is intended to hold only strings.
    // The compiler doesn't know that so we have to remember ourselves.
    List wordlist = new ArrayList();  

    // Oops! We added a String[] instead of a String.
    // The compiler doesn't know that this is an error.
    wordlist.add(args);

    // Since List can hold arbitrary objects, the get() method returns
    // Object.  Since the list is intended to hold strings, we cast the
    // return value to String but get a ClassCastException because of
    // the error above.
    String word = (String)wordlist.get(0);
}
汎用タイプは、このコードに表示されるタイプのセキュリティの問題を解決します.Java.utilのリストや他の集合クラスは汎用で書き換えられています.前述したように、リストはlistとして再定義され、その中間の要素タイプは、Eという名前の可変プレースホルダによって記述される.Add()メソッドは、以前のObjectを置換するためにEのタイプのパラメータを所望するように再定義され、get()メソッドは、以前のObjectを置換するEを返すように再定義される.
Java 5.0では、リストを明示するか、ArrayListのインスタンスを作成する場合は、汎用タイプの名前の後ろに「<>」のペアを付けて、必要な実際のタイプをカッコに書き込む必要があります.例えば、Stringを保持するListは「List  Java.utilの集合クラスの要素はオブジェクト化されている必要があります.基本的なタイプではありません.汎用的な導入はこの点を変えなかった.汎用型は基本型を使用できません.SetまたはListはこのように説明できません.覚えておいて、とにかくjava 5.0の自動パッケージングおよび自動デパッケージング特性により、SetまたはListを使用することがcharおよびint値を直接使用することと同様に便利になります.(第2章を参照して、自動パッケージ化と自動パッケージ解除の詳細について説明します).
Java 5.0では、上記の例を以下のように書き換えます.
public static void main(String[] args) {
    // This list can only hold String objects
    List<String> wordlist = new ArrayList<String>();

    // args is a String[], not String, so the compiler won't let us do this
    wordlist.add(args);  // Compilation error!

    // We can do this, though.  
    // Notice the use of the new for/in looping statement
    for(String arg : args) wordlist.add(arg);

    // No cast is required.  List<String>.get() returns a String.
    String word = wordlist.get(0);
}
注目すべきは、コード量が従来の汎用性のない例よりそれほど少なくないことだ.「(String)」というタイプ変換を使用して、タイプパラメータ「」に置き換えられます.異なるのは、タイプパラメータが必要で、一度だけ宣言する必要がありますが、listはタイプ変換を必要とせずに何度も使用できます.より長い例コードでは、この点がより顕著になります.非汎用文法よりも汎用文法が冗長に見える例でも、汎用を使用することは非常に価値があります.追加のタイプ情報により、コンパイラはコード内でより強いエラーチェックを実行できます.以前は実行中にしか見つからなかったエラーがコンパイル時に発見されました.また、以前はタイプ変換の例外を処理するために、追加のコード行を追加する必要がありました.汎用型がない場合、タイプ変換異常が発生すると、ClassCastException異常が実際のコードから投げ出されます.
1つのメソッドで任意の数のパラメータを使用できるように、クラスでは複数のタイプの変数を使用できます.インタフェースJavautil.Mapは一例です.1つのMapは、1つのkeyのオブジェクトから1つのvalueのオブジェクトへのマッピング関係を表す.インタフェースMapは、keyのタイプを記述するためのタイプ変数と、valueのタイプを記述するための別のタイプ変数とを明らかにした.たとえば、StringオブジェクトからIntegerオブジェクトへのマッピング関係を作成したいとします.
public static void main(String[] args) {
    // A map from strings to their position in the args[] array
    Map<String,Integer> map = new HashMap<String,Integer>();

    // Note that we use autoboxing to wrap i in an Integer object.
    for(int i=0; i < args.length; i++) map.put(args[i], i);  

    // Find the array index of a word.  Note no cast is required!
    Integer position = map.get("hello");

    // We can also rely on autounboxing to convert directly to an int,
    // but this throws a NullPointerException if the key does not exist
    // in the map
    int pos = map.get("world");
}
Listのような1つのパラメータタイプ自体も1つのタイプであり、他のタイプの1つのタイプ変数値として使用することもできる.次のコードが表示されます.
// Look at all those nested angle brackets!
Map<String, List<List<int[]>>> map = getWeirdMap();

// The compiler knows all the types and we can write expressions
// like this without casting.  We might still get NullPointerException
// or ArrayIndexOutOfBounds at runtime, of course.
int value = map.get(key).get(0).get(0)[0];

// Here's how we break that expression down step by step.
List<List<int[]>> listOfLists = map.get(key);
List<int[]> listOfIntArrays = listOfLists.get(0);
int[] array = listOfIntArrays.get(0);
int element = array[0];
上のコードにjava.util.Listとjava.util.Mapのget()メソッドは、Eのタイプのlist要素またはVのタイプのmap要素を返します.いずれにしても、汎用タイプは変数をより精密に使用することができることに注意してください.本書の参考章でListを参照すると、iterator()メソッドがIteratorを返すと宣言されていることがわかります.これは、この方法がlistの実際のパラメータタイプと同じパラメータタイプのインスタンスを返すことを意味する.この点を具体的に説明するために、以下の例では、get(0)メソッドを使用してリストの最初の要素を取得しない方法を提供する.
List<String> words = // ...initialized elsewhere...
Iterator<String> iterator = words.iterator();
String firstword = iterator.next();