ジェネリックとは何なのかを直接説明するとしたら、次のような質問があります。
整数、浮動小数点型、文字列型などのさまざまな型のデータを保存できる座標点クラスを定義します。
最初は変数の型が不明なので、すべての型の親クラス、つまり Object クラスを代わりに使用することが考えられます。
これ以上ナンセンスではありません。コードを使用してそれを反映してください
例 1: オブジェクトを使用して不確実なデータ型入力を実装する
// オブジェクトを使用して不確実な型を表現します
public Point(オブジェクト x, オブジェクト y) {
this.setX(x);
this.setY(y);
}
public void setX(オブジェクトx) {
this.x = x;
}
パブリック オブジェクト getX() {
x を返します。
}
public void setY(オブジェクトy) {
this.y = y;
}
パブリック オブジェクト getY() {
y を返します。
}
}
//テストクラス
パブリック クラス デモ {
public static void main(String[] args) {
System.out.println("座標を表すには浮動小数点数を使用します: ");
ポイント p = 新しいポイント(12.23,23.21);
//ここでは、Object クラスを Double クラスに変換し、自動的にアンボックス化します。 以下の 2 つは同じです。
System.out.println("X 座標" + (Double)p.getX());
System.out.println("Y 座標" + (Double)p.getY());
System.out.println();
System.out.println("座標を表すには整数を使用します: ");
ポイント p2 = 新しいポイント(12, 23);
System.out.println("X の座標" + (整数)p2.getX());
System.out.println("Y 座標" + (整数)p2.getY());
System.out.println();
System.out.println("座標を文字列として表現します: ");
ポイント p3 = new Point("北緯 29 度", "東経 113 度");
System.out.println("X 座標" + (String)p3.getX());
System.out.println("Y 座標" + (String)p3.getY());
}
}
どの型を渡しているのかを明確に理解し、それを使用する前にダウンキャストする必要があります。
これは需要を満たしていますが、危険な要素を暗示しているのはなぜですか?
たとえば、 new Point(12.23, "北緯 29 度") を使用して Point オブジェクトを構築します。
次に、(Double) を使用して下方向に変換します。結果はどうなりますか?
はい、コンパイルは成功しますが、実行すると型変換例外が発生します。
クラス変換例外を回避することも非常に簡単です。オブジェクト宣言を固定型宣言 (String x、String y など) に置き換えるだけで、コンパイル中にエラーが報告されます。
その後、間違いを見つけて修正することができます
しかし、それでは需要に応えることができなくなります。
セキュリティリスクを回避し、さまざまなデータ型を置き換えるために、優秀な人々は JDK1.5 にジェネリックスの概念を導入しました。
ジェネリックを使用して上記のコードを書き直す方法を見てみましょう
例 2: ジェネリック クラス
パブリック クラス デモ {
public static void main(String[] args) {
System.out.println("座標を表すには浮動小数点数を使用します: ");
//ジェネリックで書き換えた後は、使用されるデータに対して下方変換を実行する必要はありません。
Point<Double> p = 新しい Point<Double>(12.23,23.21);
System.out.println("X 座標" + p.getX());
System.out.println("Y 座標" + p.getY());
System.out.println();
System.out.println("座標を表すには整数を使用します: ");
ポイント<整数> p2 = 新しいポイント<整数>(12, 23);
System.out.println("X 座標" + p2.getX());
System.out.println("Y 座標" + p2.getY());
System.out.println();
System.out.println("座標を文字列として表現します: ");
Point<String> p3 = new Point<String>("北緯 29 度"、"東経 113 度");
System.out.println("X 座標" + p3.getX());
System.out.println("Y 座標" + p3.getY());
}
}
この時点で意図的に異なるデータ型を渡す場合:
Point<Double> p = new Point<Double>("北緯 29 度",12.22);
その後、コンパイル中にエラーが報告されます
ジェネリックが定義されていますが、コンストラクターでジェネリックのメカニズムを使用しない場合、データはオブジェクトとして扱われます。
これの主な目的は、次のような JDK1.4 より前の古いコードと互換性を持たせることです。
ポイント p = 新しいポイント(22.11,23.21);
最終的な実行結果は同じですが、コンパイル中に警告メッセージが表示されます。
例 3: 一般的なメソッド
上記の例からわかるように、コンストラクターでオブジェクト型を指定すると、クラス全体で同じ型が使用されます。
最も典型的な例は、次のようなコレクション フレームワークで使用されます。 ArrayList<Integer> al = new ArrayList<Integer>();
このとき、al で操作するオブジェクトの種類はすべて Integer です。
しかし、運用対象を固定するのではなく、汎用技術をより柔軟に利用したい場合もあります。
現時点では、一般的な方法を試すことができます
public <E> void show(E e) {
System.out.println(e);
}
}
パブリック クラス デモ {
public static void main(String[] args) {
Print p = new Print();
p.print(12);
p.print("こんにちは");
p.show(new Integer(33));
p.show(23);
}
}
実際、この方法では、メソッド内で Object オブジェクトを使用する場合と大きな違いはありません。
さらに、JDK1.5以降では自動アンボックス機能が追加され、下方変換が不要になりました。
例 4: 汎用インターフェース
//実装方法 1:
class InterDemo1 は Inter<String> {を実装します。
public void print(String t) {
System.out.println("print: " + t);
}
}
//実装方法2:
class InterDemo2<T> は Inter<T> を実装します {
public void print(T t) {
System.out.println("print: " + t);
}
}
クラスデモ {
public static void main(String[] args) {
InterDemo1 id1 = 新しい InterDemo1();
id1.print("こんにちは");
InterDemo2<Integer> id2 = new InterDemo2<Integer>();
id2.print(新しい整数(23));
}
}
ジェネリック インターフェイスを実装するには 2 つの方法があります。1 つは、実装時にジェネリック型を指定する方法です。
もう 1 つは、引き続きジェネリックを使用し、構築中にジェネリック タイプを決定することです。