CodeGym /Java Course /モジュール 1 /Java のパラメータ化された型: ジェネリックス

Java のパラメータ化された型: ジェネリックス

モジュール 1
レベル 16 , レッスン 6
使用可能

1. すべてのクラスは継承しますObject

Java のすべてのクラスは暗黙的にObjectクラスを継承します。

Java Core クエストでは、継承とは何か、そしてそれが Java でどのように機能するかを分析します。ここでは、これから導き出される 1 つの単純な事実について考えてみましょう。

任意のクラスのオブジェクトをObject変数に割り当てることができます。例:

コード ノート
Object o = new Scanner(System.in);
変数にはオブジェクトoへの参照が格納されますScanner
Object o = new String();
変数にはオブジェクトoへの参照が格納されますString
Object o = new Integer(15);
変数にはオブジェクトoへの参照が格納されますInteger
Object o = "Hello";
変数にはオブジェクトoへの参照が格納されますString

良いニュースはこれで終わります。コンパイラは変数に保存されたオブジェクトの元の型を追跡しないObjectため、クラスのメソッド以外の保存されたオブジェクトのメソッドを呼び出すことはできませんObject

オブジェクトの元の型に関連付けられたメソッドを呼び出す必要がある場合は、まずそのオブジェクトへの参照を正しい型の変数に保存してから、その変数のメソッドを呼び出す必要があります。

コード ノート
Object o = new Scanner(System.in);
int x = o.nextInt();
プログラムはコンパイルできません。クラスにはメソッドObjectがありませんnextInt()
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
これはうまくいきます。ここでは、タイプキャスト演算子を使用して、オブジェクト

への参照を変数に保存します。 ScannerScanner

変数にオブジェクトへの参照が格納されているObject場合でも、単に変数をスキャナ変数に割り当てることはできません。ObjectScannerただし、すでにご存知のtypecast 演算子を使用すれば、これを行うことができます。一般的な外観は次のとおりです。

Type name1 = (Type) name2;

ここでname1、 は変数の名前Type、 はオブジェクトへの参照を格納する変数name2の名前です。ObjectType

タイプキャスト

変数の型とオブジェクトの型が一致しない場合は、 がClassCastExceptionスローされます。例:

コード ノート
Object o = new Integer(5);
String s = (String) o;
実行時にエラーが発生します:ここで
a がClassCastExceptionスローされます

Java ではこのエラーを回避する方法があります。変数に格納されているオブジェクトの型をチェックすることでこれを回避します。

name instanceof Type

演算子は変数がオブジェクトinstanceofかどうかをチェックします。nameType

例として、さまざまなオブジェクトの配列内で文字列を検索してみましょう。

コード ノート
Object[] objects = {10, "Hello", 3.14};

for (int i = 0; i < objects.length; i++)
{
   if (objects[i] instanceof String)
   {
      String s = (String) objects[i];
      System.out.println(s);
   }
}
Integerオートボクシングは、これらの値をそれぞれ、String、およびに変換しますDouble

オブジェクトの配列をループします。

オブジェクトが の場合、それを変数String

に保存します 。 変数を画面に表示します。 String


2. ジェネリックが登場した理由 — コレクション

コレクションの話に戻りましょう。

Java 開発者はクラスを作成するとすぐにArrayList、あらゆる種類のオブジェクトを格納できるように、それをユニバーサルにしたいと考えました。Objectそこで、要素を格納するために の配列を使用しました。

このアプローチの利点は、任意のタイプのオブジェクトをコレクションに追加できることです。

もちろん、いくつかの弱点があります。

デメリット1.

コレクションから要素を取得するときは、常に型変換演算子を記述する必要がありました。

コード ノート
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 10);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Objectオブジェクトへの参照を保存するコレクションを作成します。

コレクションに数字10、、、20...を入力します100



コレクションの要素を合計する


型キャストが必要です

デメリット2.

コレクションに特定の種類の要素が含まれるという保証はありませんでした

コード ノート
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 2.5);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Objectオブジェクトへの参照を保存するコレクションを作成します。オブジェクト

として表される数値をコレクションに入力します。 、、、 ... コレクションの要素を合計します。 エラーが発生します。 a はan にキャストできません。Double
0.02.55.0





DoubleInteger

データはどこにでもコレクションに入れることができます。

  • 別の方法で
  • 別の番組で
  • ファイルから
  • ネットワーク経由で

デメリット3.

コレクション内のデータは誤って変更される可能性があります。

データが含まれたコレクションを何らかのメソッドに渡すことができます。このメソッドは別のプログラマによって作成され、そのデータをコレクションに追加します。

コレクションの名前は、そこに保存できるデータの種類を明確に示していません。また、変数に明確な名前を付けたとしても、その変数への参照は多数のメソッドに渡される可能性があり、それらのメソッドは変数の元の名前について何も知りません。


3. ジェネリック医薬品

Java のジェネリックス

Java では、こうした問題はすべて、ジェネリックと呼ばれる優れた機能によって解決されます。

Java では、ジェネリックとは、型パラメータを型に追加する機能を意味します。結果は、複雑な複合型になります。このような複合型の一般的な見方は次のとおりです。

ClassName<TypeParameter>

これは汎用クラスです。また、通常授業を使用する場所であればどこでも使用できます。

コード 説明
ArrayList<Integer> list;
変数の作成
list = new ArrayList<Integer> ();
オブジェクトの作成
ArrayList<Integer>[] array;
配列の作成

Integerこのようなコレクションには変数のみを保存できます。

コード 説明
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListInteger要素を含むコレクション
これは許可されており
、これも機能します
オートボクシング

しかし、これは許可されません:コンパイルエラー

Java コレクション クエストでは、型パラメーターを使用して独自のクラスを作成する方法を学びます。ここでは、それらの使用方法と機能を見ていきます。


4. ジェネリック医薬品の仕組み

実際のところ、ジェネリック医薬品は非常に原始的なものです。

コンパイラは単にジェネリック型を通常の型に置き換えます。ただし、ジェネリック型のメソッドが使用される場合、コンパイラは、パラメーターを型パラメーターにキャストするための型キャスト演算子を追加します。

コード コンパイラが行うこと
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList list = new ArrayList();
list.add(1);
list.add( (Integer) 1 );
int x = list.get(0);
int x = (Integer) list.get(0);
list.set(0, 10);
list.set(0, (Integer) 10);

整数のコレクション内の数値を合計するメソッドがあるとします。

コード コンパイラが行うこと
public int sum(ArrayList<Integer> numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + numbers.get(i);

   return result;
}
public int sum(ArrayList numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + (Integer) numbers.get(i);

   return result;
}

言い換えれば、ジェネリックはオートボクシングと同じような一種の糖衣構文ですが、それを少し上回るものです。オートボックス化を使用すると、コンパイラはintと を変換するメソッドInteger、またはその逆の変換メソッドを追加し、ジェネリックの場合は型キャスト演算子を追加します。

コンパイラーが型パラメーターを使用してジェネリック クラスをコンパイルした後、それらは通常のクラスと型キャスト演算子に単純に変換されます。ジェネリック型の変数に渡された型引数に関する情報は失われます。この効果は、タイプ消去とも呼ばれます。

ジェネリック クラス (型パラメーターを持つクラス) を作成するプログラマーは、引数として渡される型に関する情報を実際に必要とする場合があります。Java Collections クエストでは、これに対処する方法とそれに伴う内容について学びます。



5. ジェネリック医薬品に関するいくつかの事実

ジェネリック医薬品に関するさらに興味深い事実をいくつか紹介します。

クラスには複数の型パラメータを含めることができます。次のようになります。

ClassName<TypeParameter1, TypeParameter2, TypeParameter3>

実際、これはそれほど驚くべきことではありません。コンパイラが 1 つの型にキャストする演算子を追加できる場所であればどこでも、複数の型キャスト演算子を追加できます。

例:

コード ノート
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
メソッドputの最初のパラメータは でInteger、2 番目のパラメータはString

ジェネリック型もパラメータとして使用できます。次のようになります。

ClassName<TypeParameter<TypeParameterParameter>>

文字列のリストを格納するリストを作成するとします。この場合、次のような結果が得られます。

// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");

// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");

// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);

ジェネリック型 (型パラメータを持つ型) も配列型として使用できます。次のようになります。

ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];

ここでは魔法のようなことは何も起こっていません。山括弧は型名を示しているだけです。

コード 非ジェネリック対応物
ArrayList<String>[] list = new ArrayList<String>[10];
StringArrayList[] list = new StringArrayList[10];
ArrayList<Integer>[] list = new ArrayList<Integer>[10];
IntegerArrayList[] list = new IntegerArrayList[10];
ArrayList<Scanner>[] list = new ArrayList<Scanner>[10];
ScannerArrayList[] list = new ScannerArrayList[10];
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION