JavaRush /Java Blog /Random-JA /Javaのジェネリックとは何ですか

Javaのジェネリックとは何ですか

Random-JA グループに公開済み
こんにちは!今日はジェネリック医薬品についてお話します。たくさんの新しいことを学ぶことになると言わざるを得ません。これだけでなく、次の数回の講義ではジェネリック医薬品についても取り上げます。 Java のジェネリックとは - 1 したがって、このトピックに興味があれば、あなたは幸運です。今日はジェネリックの機能について多くのことを学ぶことができます。まあ、そうでない場合は、落ち着いてリラックスしてください!:) これは非常に重要なトピックなので、知っておく必要があります。まずは簡単な「何を」と「なぜ」から始めましょう。ジェネリック医薬品とは何ですか? ジェネリックはパラメーターを持つ型です。 ジェネリックを作成するときは、その型だけでなく、処理するデータの型も指定します。最も明白な例はすでに頭の中に浮かんでいると思います - これは ArrayList です。通常、プログラムでこれを作成する方法は次のとおりです。
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<String> myList1 = new ArrayList<>();
       myList1.add("Test String 1");
       myList1.add("Test String 2");
   }
}
ご想像のとおり、リストの特徴は、リストにすべてを「詰め込む」ことができないことです。リストはオブジェクトのみで動作しますString。ここで、Java の歴史を少し振り返って、「なぜ?」という質問に答えてみましょう。これを行うために、私たち自身が ArrayList クラスの簡略版を作成します。私たちのリストは内部配列にデータを追加し、このデータを受け取ることしかできません。
public class MyListClass {

   private Object[] data;
   private int count;

   public MyListClass() {
       this.data = new Object[10];
       this.count = 0;
   }

   public void add(Object o) {
       this.data[count] = o;
       count++;
   }

   public Object[] getData() {
       return data;
   }
}
リストに数値のみを保存したいとしますInteger。ジェネリック医薬品はありません。Integerでcheck の o インスタンスを明示的に指定することはできませんadd()。その場合、クラス全体は にのみ適しておりInteger、世界中に存在するすべてのデータ型に対して同じクラスを作成する必要があります。私たちはプログラマーに頼ることに決め、コードにコメントを残すだけで、プログラマーが不必要なものを追加しないようにします。
//use it ONLY with Integer data type
public void add(Object o) {
   this.data[count] = o;
   count++;
}
プログラマーの 1 人はこのコメントを見逃し、うっかり文字列と混合した数値をリストに入れて、その合計を計算しようとしました。
public class Main {

   public static void main(String[] args) {

       MyListClass list = new MyListClass();
       list.add(100);
       list.add(200);
       list.add("Lolkek");
       list.add("Shalala");

       Integer sum1 = (Integer) list.getData()[0] + (Integer) list.getData()[1];
       System.out.println(sum1);

       Integer sum2 = (Integer) list.getData()[2] + (Integer) list.getData()[3];
       System.out.println(sum2);
   }
}
コンソール出力: 300 スレッド "main" java.lang.ClassCastException の例外: java.lang.String を Main.main(Main.java:14) で java.lang.Integer にキャストできません この状況で最悪なのは何でしょうか? プログラマの不注意とは程遠い。最悪の場合は、間違ったコードがプログラム内の重要な場所に配置され、正常にコンパイルされてしまうことです。ここで、エラーはコーディング段階ではなく、テスト段階でのみ確認されます (これは最良の場合です!)。 開発の後半でバグを修正すると、お金と時間の両方でかなりのコストがかかります。 これはまさにジェネリックの利点です。ジェネリック クラスを使用すると、運が悪いプログラマでも即座にエラーを検出できます。コードは単純にコンパイルできません。
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Integer> myList1 = new ArrayList<>();

       myList1.add(100);
       myList1.add(100);
       myList1.add("Lolkek");//error!
       myList1.add("Shalala");//error!
   }
}
プログラマーはすぐに「我に返り」、即座に自分自身を修正します。ちなみに、Listこの種のエラーを確認するために独自のクラスを作成する必要はありませんでした。<Integer>通常の ArrayList から 型括弧 ( ) を削除するだけです。
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

      List list = new ArrayList();

      list.add(100);
      list.add(200);
      list.add("Lolkek");
      list.add("Shalala");

       System.out.println((Integer) list.get(0) + (Integer) list.get(1));
       System.out.println((Integer) list.get(2) + (Integer) list.get(3));
   }
}
コンソール出力: 300 Exception in thread "main" java.lang.ClassCastException: java.lang.String can be Cast to java.lang.Integer at Main.main(Main.java:16) つまり、「ネイティブ」ツールを使用してもJava の場合、この間違いを犯して安全でないコレクションを作成する可能性があります。ただし、このコードを IDEa に貼り付けると、「java.util.List の生の型のメンバーとしての add(E) の呼び出しがチェックされていません」という警告が表示されます。これは、要素を IDEa に追加するときに問題が発生する可能性があることを示しています。ジェネリックを使用しないコレクションはこの方法ではありません。しかし、「生の型」という言葉は何を意味するのでしょうか? 文字通りの翻訳は非常に正確です - 「生のタイプ」または「ダーティタイプ」。 Raw type型が削除されたジェネリック クラスです。 つまり、List myList1これは ですRaw type。その反対は、型指定を使用して正しく作成されたジェネリック クラス ( class とも呼ばれます)raw typeです。例えば、。なぜ使用が許可されているのかと疑問に思うかもしれません。理由は簡単です。Java の作成者は、互換性の問題が発生しないように、Java のサポートを残しました。Java 5.0 がリリースされるまでに (このバージョンで初めてジェネリックが登場しました)、多くのコードがすでに を使用して記述されていました。したがって、この可能性は今日でもまだ存在します。Joshua Bloch の古典的な本「Effective Java」については、すでに講義で何度か言及しました。この言語の作成者の 1 人として、彼は本の中でと の使用に関するトピックを無視しませんでした。 この本の第 23 章には、「新しいコードでは生の型を使用しないでください」という非常に雄弁なタイトルが付いています 。これは覚えておく必要があります。ジェネリック クラスを使用する場合は、決して に変換しないでください。 generic typeparameterized typeList<String> myList1raw typesraw typesraw typesraw typesgeneric typesJava のジェネリックとは - 2generic typeraw type

型付きメソッド

Java では、個別のメソッドを入力して、いわゆるジェネリック メソッドを作成できます。なぜそのような方法が便利なのでしょうか?まず第一に、さまざまなタイプのパラメーターを操作できるためです。同じロジックを異なる型に安全に適用できる場合は、汎用メソッドが優れたソリューションになります。例を見てみましょう。ある種のリストがあるとしましょうmyList1。そこからすべての値を削除し、すべての空きスペースを新しい値で埋めたいと考えています。ジェネリック メソッドを使用したクラスは次のようになります。
public class TestClass {

   public static <T> void fill(List<T> list, T val) {
       for (int i = 0; i < list.size(); i++)
           list.set(i, val);
   }

   public static void main(String[] args) {

       List<String> strings = new ArrayList<>();
       strings.add("Старая строка 1");
       strings.add("Старая строка 2");
       strings.add("Старая строка 3");

       fill(strings, "Новая строка");

       System.out.println(strings);

       List<Integer> numbers = new ArrayList<>();
       numbers.add(1);
       numbers.add(2);
       numbers.add(3);

       fill(numbers, 888);
       System.out.println(numbers);
   }
}
構文に注意してください。少し変わっています。
public static <T> void fill(List<T> list, T val)
戻り値の型の前に <T> が付き、ジェネリック メソッドであることを示します。この場合、メソッドは入力として 2 つのパラメーターを取ります。オブジェクト T のリストと別の別のオブジェクト T です。<T> を使用することで、メソッドの型指定が実現されます。そこに文字列のリストと数値を渡すことはできません。文字列のリストと文字列、数値のリストと数値、オブジェクトのリストCatと別のオブジェクトCat- それが唯一の方法です。この方法は、さまざまな種類のデータを簡単に処理できるmain()ことを明確に示していますfill()。まず、文字列のリストと文字列を入力として受け取り、次に数値のリストと数値を受け取ります。 コンソール出力: [Newline, Newline, Newline] [888, 888, 888]fill() 30 の異なるクラスのメソッド ロジックが必要で、ジェネリック メソッドがなかった 場合を想像してください。データ型が異なるだけで、同じメソッドを 30 回記述する必要があります。しかし、汎用メソッドのおかげで、コードを再利用できます。:)

型付きクラス

Java で提供される汎用クラスを使用するだけでなく、独自のクラスを作成することもできます。簡単な例を次に示します。
public class Box<T> {

   private T t;

   public void set(T t) {
       this.t = t;
   }

   public T get() {
       return t;
   }

   public static void main(String[] args) {

       Box<String> stringBox = new Box<>();

       stringBox.set("Старая строка");
       System.out.println(stringBox.get());
       stringBox.set("Новая строка");

       System.out.println(stringBox.get());

       stringBox.set(12345);//ошибка компиляции!
   }
}
私たちのクラスBox<T>(「ボックス」) は型付きです。作成時にデータ型 ( ) を割り当てると<T>、他の型のオブジェクトをそこに配置できなくなります。これは例で見ることができます。作成時に、オブジェクトが文字列を処理するように指定しました。
Box<String> stringBox = new Box<>();
コードの最後の行で、ボックス内に数値 12345 を入力しようとすると、コンパイル エラーが発生します。このようにして、独自のジェネリック クラスを作成しました。:) これで今日の講義は終わりです。しかし、私たちはジェネリック医薬品に別れを告げているわけではありません。次の講義では、より高度な機能について説明しますので、さよならを言わないでください。)勉強頑張ってください!:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION