Java のジェネリックス

ジェネリック 手段 パラメータ化された型 。その考え方は、型 (Integer、String など、およびユーザー定義型) をメソッド、クラス、インターフェイスのパラメーターとして使用できるようにすることです。ジェネリックを使用すると、さまざまなデータ型を処理するクラスを作成できます。パラメータ化された型を操作するクラス、インターフェイス、メソッドなどのエンティティは、ジェネリック エンティティです。

なぜジェネリックなのか?

物体 は他のすべてのクラスのスーパークラスであり、オブジェクト参照は任意のオブジェクトを参照できます。これらの機能にはタイプ セーフティがありません。ジェネリック医薬品には、その種の安全機能が追加されています。この種の安全機能については、後の例で説明します。

Java のジェネリックは C++ のテンプレートに似ています。たとえば、HashSet、ArrayList、HashMap などのクラスはジェネリックスをうまく使用します。ジェネリック型に対する 2 つのアプローチには、基本的な違いがいくつかあります。

Java ジェネリックの種類

一般的な方法: 汎用 Java メソッドはパラメータを受け取り、タスクの実行後に値を返します。これは通常の関数とまったく同じですが、ジェネリック メソッドには実際の型によって引用される型パラメーターがあります。これにより、ジェネリック メソッドをより一般的な方法で使用できるようになります。コンパイラは型の安全性を処理するため、プログラマは長い個別の型キャストを実行する必要がないため、簡単にコードを作成できます。

汎用クラス: ジェネリック クラスは、非ジェネリック クラスとまったく同じように実装されます。唯一の違いは、型パラメーター セクションが含まれていることです。複数のタイプのパラメータをカンマで区切って指定できます。 1 つ以上のパラメーターを受け入れるクラスは、パラメーター化されたクラスまたはパラメーター化された型として知られています。

ジェネリッククラス

C++ と同様に、ジェネリック クラスの作成時にパラメーターの型を指定するために使用します。ジェネリック クラスのオブジェクトを作成するには、次の構文を使用します。

// To create an instance of generic class BaseType obj = new BaseType () 

注記: パラメータタイプでは、「int」、「char」、「double」などのプリミティブは使用できません。

ジャワ




// Java program to show working of user defined> // Generic classes> // We use to specify Parameter type> class> Test {> > // An object of type T is declared> > T obj;> > Test(T obj) {> this> .obj = obj; }> // constructor> > public> T getObject() {> return> this> .obj; }> }> // Driver class to test above> class> Main {> > public> static> void> main(String[] args)> > {> > // instance of Integer type> > Test iObj => new> Test(> 15> );> > System.out.println(iObj.getObject());> > // instance of String type> > Test sObj> > => new> Test(> 'GeeksForGeeks'> );> > System.out.println(sObj.getObject());> > }> }>

出力

15 GeeksForGeeks 

ジェネリック クラスで複数の Type パラメーターを渡すこともできます。

ジャワ




// Java program to show multiple> // type parameters in Java Generics> // We use to specify Parameter type> class> Test> {> > T obj1;> // An object of type T> > U obj2;> // An object of type U> > // constructor> > Test(T obj1, U obj2)> > {> > this> .obj1 = obj1;> > this> .obj2 = obj2;> > }> > // To print objects of T and U> > public> void> print()> > {> > System.out.println(obj1);> > System.out.println(obj2);> > }> }> // Driver class to test above> class> Main> {> > public> static> void> main (String[] args)> > {> > Test obj => > new> Test(> 'GfG'> ,> 15> );> > obj.print();> > }> }>

出力

GfG 15 

汎用関数:

ジェネリック メソッドに渡される引数のタイプに基づいて、さまざまなタイプの引数を使用して呼び出すことができるジェネリック関数を作成することもできます。コンパイラは各メソッドを処理します。

ジャワ




// Java program to show working of user defined> // Generic functions> class> Test {> > // A Generic method example> > static> > void> genericDisplay(T element)> > {> > System.out.println(element.getClass().getName()> > +> ' = '> + element);> > }> > // Driver method> > public> static> void> main(String[] args)> > {> > // Calling generic method with Integer argument> > genericDisplay(> 11> );> > // Calling generic method with String argument> > genericDisplay(> 'GeeksForGeeks'> );> > // Calling generic method with double argument> > genericDisplay(> 1.0> );> > }> }>

出力

java.lang.Integer = 11 java.lang.String = GeeksForGeeks java.lang.Double = 1.0 

ジェネリックは参照型でのみ機能します。

ジェネリック型のインスタンスを宣言する場合、type パラメーターに渡される型引数は参照型である必要があります。のようなプリミティブなデータ型は使用できません。 整数 チャー。

Test obj = new Test(20); 

上記の行ではコンパイル時エラーが発生しますが、このエラーは型ラッパーを使用してプリミティブ型をカプセル化することで解決できます。

ただし、配列は参照型であるため、プリミティブ型配列を型パラメーターに渡すことができます。

ArrayList a = new ArrayList(); 

ジェネリック型は型引数に基づいて異なります。

次の Java コードを考えてみましょう。

ジャワ




// Java program to show working> // of user-defined Generic classes> // We use to specify Parameter type> class> Test {> > // An object of type T is declared> > T obj;> > Test(T obj) {> this> .obj = obj; }> // constructor> > public> T getObject() {> return> this> .obj; }> }> // Driver class to test above> class> Main {> > public> static> void> main(String[] args)> > {> > // instance of Integer type> > Test iObj => new> Test(> 15> );> > System.out.println(iObj.getObject());> > // instance of String type> > Test sObj> > => new> Test(> 'GeeksForGeeks'> );> > System.out.println(sObj.getObject());> > iObj = sObj;> // This results an error> > }> }>

出力:

error: incompatible types: Test cannot be converted to Test 

iObj と sObj は Test 型ですが、型パラメーターが異なるため、異なる型への参照になります。ジェネリックスはこれによって型の安全性を追加し、エラーを防ぎます。

Java ジェネリックスの型パラメータ

型パラメーターの命名規則は、ジェネリックを徹底的に学習するために重要です。共通の型パラメータは次のとおりです。

  • T – タイプ
  • E – 要素
  • K – キー
  • N – 番号
  • V – 値

ジェネリック医薬品の利点:

ジェネリックを使用するプログラムには、非ジェネリック コードに比べて多くの利点があります。

1. コードの再利用: メソッド/クラス/インターフェイスを一度作成すれば、それを必要な型に使用できます。

2. タイプセーフティ: ジェネリックスでは、実行時ではなくコンパイル時にエラーが発生します (コードを実行時に失敗させるよりも、コンパイル時にコードの問題を知る方が常に良いです)。学生の名前を格納する ArrayList を作成するとします。プログラマが誤って文字列ではなく整数オブジェクトを追加した場合、コンパイラはそれを許可します。ただし、このデータを ArrayList から取得すると、実行時に問題が発生します。

ジャワ




// Java program to demonstrate that NOT using> // generics can cause run time exceptions> import> java.util.*;> class> Test> {> > public> static> void> main(String[] args)> > {> > // Creatinga an ArrayList without any type specified> > ArrayList al => new> ArrayList();> > al.add(> 'Sachin'> );> > al.add(> 'Rahul'> );> > al.add(> 10> );> // Compiler allows this> > String s1 = (String)al.get(> 0> );> > String s2 = (String)al.get(> 1> );> > // Causes Runtime Exception> > String s3 = (String)al.get(> 2> );> > }> }>

出力:

Exception in thread 'main' java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Test.main(Test.java:19) 

ジェネリックはこの問題をどのように解決するのでしょうか?

ArrayList を定義するとき、このリストが String オブジェクトのみを取ることを指定できます。

ジャワ




// Using Java Generics converts run time exceptions into> // compile time exception.> import> java.util.*;> class> Test> {> > public> static> void> main(String[] args)> > {> > // Creating a an ArrayList with String specified> > ArrayList al => new> ArrayList ();> > al.add(> 'Sachin'> );> > al.add(> 'Rahul'> );> > // Now Compiler doesn't allow this> > al.add(> 10> );> > String s1 = (String)al.get(> 0> );> > String s2 = (String)al.get(> 1> );> > String s3 = (String)al.get(> 2> );> > }> }>

出力:

15: error: no suitable method found for add(int) al.add(10); ^ 

3. 個別の型キャストは必要ありません。 ジェネリックスを使用しない場合、上記の例では、ArrayList からデータを取得するたびに、それを型キャストする必要があります。検索操作のたびに型キャストするのは大きな頭痛の種です。リストに文字列データのみが含まれることがすでにわかっている場合は、毎回それを型キャストする必要はありません。

ジャワ




// We don't need to typecast individual members of ArrayList> import> java.util.*;> class> Test {> > public> static> void> main(String[] args)> > {> > // Creating a an ArrayList with String specified> > ArrayList al => new> ArrayList();> > al.add(> 'Sachin'> );> > al.add(> 'Rahul'> );> > // Typecasting is not needed> > String s1 = al.get(> 0> );> > String s2 = al.get(> 1> );> > }> }>

4. ジェネリックスはコードの再利用性を促進します。 Java のジェネリックを利用すると、さまざまな種類のデータを処理するコードを作成できます。例えば、

int、char、String などのさまざまなデータ型の配列要素を並べ替えたいとします。

基本的に、データ型ごとに異なる関数が必要になります。

簡単にするために、バブルソートを使用します。

しかし、使用することで ジェネリック医薬品、 コードの再利用機能を実現できます。

ジャワ




public> class> GFG {> > public> static> void> main(String[] args)> > {> > Integer[] a = {> 100> ,> 22> ,> 58> ,> 41> ,> 6> ,> 50> };> > Character[] c = {> 'v'> ,> 'g'> ,> 'a'> ,> 'c'> ,> 'x'> ,> 'd'> ,> 't'> };> > String[] s = {> 'Virat'> ,> 'Rohit'> ,> 'Abhinay'> ,> 'Chandu'> ,> 'Sam'> ,> 'Bharat'> ,> 'Kalam'> };> > System.out.print(> 'Sorted Integer array : '> );> > sort_generics(a);> > System.out.print(> 'Sorted Character array : '> );> > sort_generics(c);> > System.out.print(> 'Sorted String array : '> );> > sort_generics(s);> > > }> > public> static> extends Comparable>void sort_generics(T[] a) { //非プリミティブ データ型を比較しているため、 //Comparable クラスを使用する必要があります //バブル ソート ロジック for (int i = 0; i 1; i++) { for (int j = 0; j 1; j++) { if (a[j].compareTo(a[j + 1])> 0) { swap(j, j + 1, a); } } } // ソート後の要素を出力 for (T i : a) { System.out.print(i + ', '); System.out.println(); public static void swap(int i, int j, T[] a) { T t = a[i]; a[i] = a[j]; a[j] = t; } }>>

出力

Sorted Integer array : 6, 22, 41, 50, 58, 100, Sorted Character array : a, c, d, g, t, v, x, Sorted String array : Abhinay, Bharat, Chandu, Kalam, Rohit, Sam, Virat, 

ここでは、ジェネリックス メソッドを作成しました。これと同じメソッドを使用して、整数データ、文字列データなどに対する操作を実行できます。

5. 汎用アルゴリズムの実装: ジェネリックを使用すると、さまざまなタイプのオブジェクトで動作するアルゴリズムを実装でき、同時にタイプセーフでもあります。