Java
 Computer >> コンピューター >  >> プログラミング >> Java

Javaジェネリックチュートリアル-ジェネリックとは何ですか?それらの使用方法は?

Java Genericsは、Java言語の最も重要な機能の1つです。ジェネリックスの背後にある考え方は非常に単純ですが、それに関連する通常の構文からの移行のために、複雑になることがあります。

このチュートリアルの目的は、ジェネリックのこの便利な概念をわかりやすく紹介することです。

しかし、ジェネリックス自体に飛び込む前に、そもそもJavaジェネリックスが必要だった理由を理解しましょう。

Javaジェネリックの目的

Java 5にジェネリックスが導入される前は、エラーや警告をスローすることなく、次のようなコードスニペットを記述してコンパイルできました。

List list = new ArrayList();
list.add("hey");
list.add(new Object());

保存するデータのタイプを宣言しなくても、リストまたは別のJavaコレクションに任意のタイプの値を追加できます。ただし、リストから値を取得するときは、特定のタイプに明示的にキャストする必要があります。

上記のリストを繰り返すことを検討してください。

for (int i=0; i< list.size(); i++) {
    String value = (String) list.get(i);  //CastClassException when i=1
}

私たちが行ったように、最初に保存されたデータ型を宣言せずにリストの作成を許可すると、プログラマーが上記のような間違いを犯してClassCastExceptionsをスローする可能性があります。 実行時。

ジェネリックは、プログラマーがそのような間違いを犯さないようにするために導入されました。

ジェネリックスを使用すると、次の例に示すように、Javaコレクションを作成するときに格納されるデータ型を明示的に宣言できます。

注:保存されたデータ型を指定せずにJavaコレクションオブジェクトを作成することはできますが、お勧めしません。
List<String> stringList = new ArrayList<>();

これで、コンパイル時エラーをスローせずに、誤って整数を文字列型リストに格納することはできません。これにより、プログラムでランタイムエラーが発生することがなくなります。

stringList.add(new Integer(4)); //Compile time Error

Javaにジェネリックスを導入する主な目的は、ClassCastExceptionsに遭遇しないようにすることでした。 実行時。

Javaジェネリックの作成

ジェネリックスを使用して、Javaクラスとメソッドを作成できます。各タイプのジェネリックを作成する方法の例を見てみましょう。

ジェネリッククラス

ジェネリッククラスを作成する場合、クラスのtypeパラメーターは、角度<>内のクラス名の最後に追加されます。 ブラケット。

public class GenericClass<T> {
    private T item;
    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return this.item;
    }
}

ここでは、T データ型パラメータです。 TN 、およびE Javaの規則に従ってデータ型パラメータに使用される文字の一部です。

上記の例では、GenericClassオブジェクトを作成するときに特定のデータ型を渡すことができます。

public static void main(String[] args) {

    GenericClass<String> gc1 = new GenericClass<>();
    gc1.setItem("hello");
    String item1 = gc1.getItem(); // "hello"
    gc1.setItem(new Object()); //Error

    GenericClass<Integer> gc2 = new GenericClass<>();
    gc2.setItem(new Integer(1));
    Integer item2 = gc2.getItem(); // 1
    gc2.setItem("hello"); //Error
}

ジェネリッククラスオブジェクトを作成するときに、プリミティブデータ型をデータ型パラメーターに渡すことはできません。タイプパラメータとして渡すことができるのは、オブジェクトタイプを拡張するデータ型のみです。

例:

GenericClass<float> gc3 = new GenericClass<>(); //Error
ジェネリックメソッド

ジェネリックメソッドの作成は、ジェネリッククラスの作成と同様のパターンに従います。ジェネリッククラス内だけでなく、非ジェネリッククラス内にもジェネリックメソッドを実装できます。

public class GenericMethodClass {

    public static <T> void printItems(T[] arr){
        for (int i=0; i< arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    public static void main(String[] args) {
        String[] arr1 = {"Cat", "Dog", "Mouse"};
        Integer[] arr2 = {1, 2, 3};

        GenericMethodClass.printItems(arr1); // "Cat", "Dog", "Mouse"
        GenericMethodClass.printItems(arr2); // 1, 2, 3
    }
}

ここでは、特定のタイプの配列を渡して、メソッドをパラメーター化できます。汎用メソッドPrintItems() 渡された配列を反復処理し、通常のJavaメソッドと同じように格納されているアイテムを出力します。

有界型パラメーター

これまでのところ、上記で作成したジェネリッククラスとメソッドは、プリミティブ型以外の任意のデータ型にパラメーター化できます。しかし、ジェネリックスに渡すことができるデータ型を制限したい場合はどうでしょうか。ここで、制限付きタイプのパラメーターが役立ちます。

別のデータ型のサブクラスである必要があることを指定することにより、ジェネリッククラスまたはメソッドで受け入れられるデータ型をバインドできます。

例:

//accepts only subclasses of List
public class UpperBoundedClass<T extends List>{
    //accepts only subclasses of List
    public <T extends List> void UpperBoundedMethod(T[] arr) {
    }
}

ここでは、UpperBoundedClass およびUpperBoundedMethod Listのサブタイプを使用してのみパラメータ化できます データ型。

List データ型は、型パラメーターの上限として機能します。 Listのサブタイプではないデータ型を使用しようとした場合 、コンパイル時エラーがスローされます。

境界はクラスだけに限定されません。インターフェイスを渡すこともできます。インターフェイスを拡張するということは、この場合、インターフェイスを実装することを意味します。

この例が示すように、パラメータは複数の境界を持つこともできます。

//accepts only subclasses of both Mammal and Animal
public class MultipleBoundedClass<T extends Mammal & Animal>{

    //accepts only subclasses of both Mammal and Animal
    public <T extends Mammal & Animal> void MultipleBoundedMethod(T[] arr){

    }
}

受け入れるデータ型は、AnimalクラスとMammalクラスの両方のサブクラスである必要があります。これらの境界の1つがクラスである場合、それは境界宣言の最初に来る必要があります。

上記の例で、Mammalがクラスであり、Animalがインターフェースである場合、上記のようにMammalが最初に来る必要があります。それ以外の場合、コードはコンパイル時エラーをスローします。

JavaGenericsワイルドカード

ワイルドカードは、ジェネリック型のパラメーターをメソッドに渡すために使用されます。ジェネリックメソッドとは異なり、ここでは、ジェネリックパラメーターはメソッドによって受け入れられるパラメーターに渡されます。これは、上記で説明したデータ型パラメーターとは異なります。ワイルドカードは?で表されます。シンボル。

public void printItems(List<?> list) {
    for (int i=0; i< list.size(); i++) {
        System.out.println(list.get(i));
    }
}

上記のprintItems() メソッドは、任意のデータ型のリストをパラメーターとして受け入れます。これにより、プログラマーは、ジェネリックスがない場合のように、さまざまなデータ型のリストに対してコードを繰り返す必要がなくなります。

上界と下界のワイルドカード

メソッドで受け入れられるリストに格納されるデータ型を制限する場合は、制限付きワイルドカードを使用できます。

例:

public void printSubTypes(List<? extends Color> list) {
    for (int i=0; i< list.size(); i++) {
        System.out.println(list.get(i));
    }
}

printSubTypes() メソッドは、Colorのサブタイプを格納するリストのみを受け入れます。 RedColorまたはBlueColorオブジェクトのリストを受け入れますが、Animalオブジェクトのリストは受け入れません。これは、動物が色のサブタイプではないためです。これは、上界と下界のワイルドカードの例です。

下限ワイルドカード

同様に、次の場合:

public void printSuperTypes(List<? super Dog> list) {
    for (int i=0; i< list.size(); i++) {
        System.out.println(list.get(i));
    }
}

次に、printSuperTypes() メソッドは、Dogクラスのスーパータイプを格納するリストのみを受け入れます。 LabDogはDogのスーパークラスではなくサブクラスであるため、哺乳類または動物のオブジェクトのリストは受け入れますが、LabDogオブジェクトのリストは受け入れません。これは、下限のワイルドカードの例です。

結論

Java Genericsは、導入以来、プログラマーがなくてはならない機能になっています。

この人気は、プログラマーの生活を楽にすることへの影響によるものです。ジェネリックスを使用すると、コーディングミスを防ぐ以外に、コードの繰り返しが少なくなります。異なるデータ型に対してコードを繰り返す必要がないように、クラスとメソッドを一般化する方法に気づきましたか?

ジェネリックスをよく理解することは、言語の専門家になるために重要です。したがって、このチュートリアルで学んだことを実際のコードに適用することが、今前進する方法です。


  1. Google アシスタント ルーチンとその設定方法

    Google アシスタントのルーチンは、ユーザーが特定のフレーズを言うたびに Google アシスタントが自動的に実行する一連のアクションです。 6 つの既製の Google アシスタント ルーチンのいずれかを使用することで、この機能を簡単に使い始めることができます。ただし、クリエイティブになりたい場合は、Google アシスタントが実行できる一連のアクションを実行するカスタム Google アシスタント ルーチンを設定できます。 この記事では、既製の 6 つのルーティンを紹介し、独自のカスタム Google アシスタント ルーティンを設定して 1 日を自動化する方法を紹介します。 Goo

  2. Windows Sysinternals:その概要と使用方法

    Windows コンピューターを完全に制御したいと思ったことはありませんか?ほぼすべての Windows プロセスまたはアプリケーションの内部を確認できるだけでなく、アプリケーションがアクセスしているファイルやレジストリ エントリをリアルタイムで表示できるというのは素晴らしいことです。 最も評判が良く強力な Windows システムおよび管理ツールキットの 1 つは Sysinternals です。ほとんどのユーティリティは単純な EXE ファイルであり、USB フラッシュ ドライブに配置することで、システム管理用の Windows ポータブル アプリのコレクションに追加できます。 Wind