Javaオブジェクト指向(XII)

ジェネリック

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

ジェネリック医薬品:ジェネリック型の広い範囲

どのようなタイプを決定するためにどのような種類、使用時には、わからない始まり

(1)定義の開始時に、ジャッキを残します

オブジェクトが作成されたとき(2)、再度、対応するタイプに挿入

ジェネリック医薬品は、として理解することができる「パラメータ化された型。」メソッドのパラメータを定義するときに表示されているに最も精通し、パラメータの言及、および引数を渡すときに、このメソッドを呼び出します。

名前が示唆するように、また、パラメータの形式(typeパラメータを参照することができる)、この時点で定義されているプロセス変数パラメータ型と同様、元のパラメータのような特定の種類は、特に着信/呼び出しを使用する場合タイプ(型引数)。

(特に一般的な指定の異なる種類によって制限型のパラメータを制御するための新しいタイプの場合には作成されていない)パラメータ化されたタイプの汎用。つまり、操作のデータ型は、クラス、インタフェースおよびメソッドのタイプに使用することができる一般的なクラス、ジェネリックインターフェイス、ジェネリックメソッドと呼ばれるパラメータとして指定されている、一般的な使用です。

一般的な定義

ジェネリッククラス:パブリッククラスのデモ {}、Tは、未知のタイプを表します。

ジェネリックインターフェイス:パブリックインターフェイスImplDemo <T、V> {}、及び(インターフェースは特別なクラスである)同じクラスを定義します。

一般的な方法:公共 ボイドDEMO1(T名){}、公衆 TのDEMO2(T tの){Tを返します;}

<>ブラケット、名前は、任意の一般的に使用されるTであってもよい:タイプ、E:要素、K:キー、V:値。

このタイプを示すために、コードのセクションを呼び出し、誰でもできる不確実性のコードテンプレートの種類、。

デフォルトのObject型であるジェネリック型を指定しない場合、

ジェネリックのメリット

型変換の例外を避けるために、(1)コンパイル時に型の、セキュリティ保証の種類を、決定します。

(2)キャストを避けるために。

(3)コードの有益な再利用を増加汎用性。

一般的な自然

ジェネリック医薬品は、実際にシンタックスシュガー、エッセンス、またはオブジェクトであるが、それは強力な内部転送を行うことはまだあります。

 
コピー
class Demo<T> { T x; public Demo(T x) { this.x = x; } public T getX() { return x; } } public class Test { public static void main(String[] args) { Demo<String> demo = new Demo<>("SSS"); String str = demo.x; System.out.println(str); } }

後にコンパイル:

 
コピー
class Demo { Object x; public Demo(Object x) { this.x = x; } public Object getX() { return x; } } public class Test { public Test() { } public static void main(String args[]) { Demo demo = new Demo("SSS"); String str = (String)demo.x; System.out.println(str); } }

一般的な方法とジェネリッククラス

(1)一般的なクラス

上記で定義されたジェネリッククラス、クラスのクラス名 {}、オブジェクトの作成では、ジェネリック型を指定します。

上記従来の方法によってのみ定義される一般的なジェネリッククラスは、上記の静的方法で使用することができません。

(2)一般的な方法

上記方法でパラメータを渡すの特定のタイプを決定するために、使用時に、ジェネリックを添加します。

あなたは一人でジェネリックを使用する方法は、意味のあるパラメータが存在しなければなりません。

 
コピー
class Demo { public <T> void demo1(T t) { System.out.println(t.getClass()); } public <T> T demo2(T t) { System.out.println(t.getClass()); return t; } public static <T> void demo3(T t) { System.out.println(t.getClass()); } } public class Test { public static void main(String[] args) { Demo demo = new Demo(); demo.demo1("str");// class java.lang.String demo.demo1(10);// class java.lang.Integer demo.demo1(10.5);// class java.lang.Double Demo.demo3(true);// class java.lang.Boolean } }

一般的なワイルドカード

ワイルドカードは:私が受け取ったときに使用するどのような種類がわからない、使用することができますか?不明なことを示します。

(1)ワイルドカードボーダレス

無制限のワイルドカードの主な役割は、ジェネリック医薬品は、データの未知のタイプを受け入れることを可能にすることです。

 
コピー
public static void printList(List<?> list) { for (Object o : list) { System.out.println(o); } } public static void main(String[] args) { List<String> l1 = new ArrayList<>(); l1.add("aa"); l1.add("bb"); l1.add("cc"); printList(l1); List<Integer> l2 = new ArrayList<>(); l2.add(11); l2.add(22); l2.add(33); printList(l2); }

この使用リスト<?>ウェイは、サブクラスのオブジェクトに親クラスの基準点です。このメソッドはがprintlist公共の静的な無効がprintlist(リストのように書くことができないことに注意してください list)的形式,虽然Object类是所有类的父类,但是List跟其他泛型的List如List , List 不存在继承关系,因此会报错。

我们不能对List<?>使用add方法,仅有一个例外,就是add(null)。 为什么呢?因为我们不确定该List的类型,不知道add什么类型的数据才对,只有null是所有引用数据类型都具有的元素

      
Copy
public static void addTest(List<?> list) { list.add(new Object()); // 编译报错 list.add(1); // 编译报错 list.add("ABC"); // 编译报错 list.add(null); } public static void main(String[] args) { List<?> list = new ArrayList<>(); addTest(list); }

由于我们根本不知道list会接受到具有什么样的泛型List,所以除了null之外什么也不能add。

还有, List<?>也不能使用get方法,只有Object类型是个例外。 原因也很简单,因为我们不知道传入的List是什么泛型的,所以无法接受得到的get,但是Object是所有数据类型的父类,所以只有接受他可以。

      
Copy
public static void getTest(List<?> list) { String s = list.get(0); // 编译报错 Integer i = list.get(1); // 编译报错 Object o = list.get(2); } public static void main(String[] args) { List<?> list = Arrays.asList(1, 2, 3, 4); getTest(list); }

(2)固定上边界的通配符

用来限定元素的类型必须得指定类的子类(包括指定类和指定类的子类)

      
Copy
public static double sumOfList(List<? extends Number> list) { double s = 0.0; for (Number n : list) { // 注意这里得到的n是其上边界类型的, 也就是Number, 需要将其转换为double. s += n.doubleValue(); } return s; } public static void main(String[] args) { List<Integer> list1 = Arrays.asList(1, 2, 3, 4); System.out.println(sumOfList(list1)); List<Double> list2 = Arrays.asList(1.1, 2.2, 3.3, 4.4); System.out.println(sumOfList(list2)); }

List<? extends E> 不能使用add方法

      
Copy
public static void addTest2(List<? extends Number> l) { // l.add(1); // 编译报错 // l.add(1.1); //编译报错 l.add(null); }

泛型<? extends E>指的是E及其子类,这里传入的可能是Integer,也可能是Double,我们在写这个方法时不能确定传入的什么类型的数据,所以除了null之外什么也不能add。但是get的时候是可以得到一个Number, 也就是上边界类型的数据的,因为不管存入什么数据类型都是Number的子类型,得到这些就是一个父类引用指向子类对象。

(3)固定下边界的通配符

用来限定元素的类型必须得指定类的父类(包括指定类和指定类的父类)

      
Copy
public static void addNumbers(List<? super Integer> list) { for (int i = 1; i <= 10; i++) { list.add(i); } } public static void main(String[] args) { List<Object> list1 = new ArrayList<>(); addNumbers(list1); System.out.println(list1); List<Number> list2 = new ArrayList<>(); addNumbers(list2); System.out.println(list2); List<Double> list3 = new ArrayList<>(); addNumbers(list3); // 编译报错 }

List<? super E>是能够调用add方法的,因为我们在addNumbers所add的元素就是Integer类型的,而传入的list不管是什么,都一定是Integer或其父类泛型的List,这时add一个Integer元素是没有任何疑问的。但是, 我们不能使用get方法,因为我们所传入的类都是Integer的类或其父类,所传入的数据类型可能是Integer到Object之间的任何类型,这是无法预料的,也就无法接收。唯一能确定的就是Object,因为所有类型都是其子类型。

泛型的限制和规则

(1)泛型的类型参数只能是引用类型,不能使用值类型(是不会自动装箱的)。

(2)泛型的类型参数可以有多个。

(3)泛型前后类型必须得要保持一致,即 ArrayList list = new ArrayList (); 从JAVA7开始,后面的类型可以不写 ArrayList list = new ArrayList<>(); 菱形语法。

(4)泛型类不是真正存在的类,不能使用instanceof运算符。

(5)泛型类的类型参数不能用在静态申明。

(6)如果定义了泛型,不指定具体类型,泛型默认指定为Ojbect类型。

(7)泛型使用?作为类型通配符,表示未知类型,可以匹配任何类型。因为是未知,所以无法添加元素。

(8)类型通配符上限:<? extends T>,?代表是T类型本身或者是T的子类型。常用于泛型方法,避免类型转换。

(9)类型通配符下限。<? super T>,?代表T类型本身或者是T的父类型。
除了通配符可以实现限制,类、接口和方法中定义的泛型参数也能限制上限和下限。

泛型擦除

泛型擦除:把泛型给去掉。

      
Copy
// 泛型擦除(把泛型给去掉) List<String> list = new ArrayList<>(); list.add("aa"); List list2 = null; list2 = list; // 把list当中的泛型给擦除掉 list2.add(10); list2.add("bb"); System.out.println(list2);
posted @ 2019-08-04 15:06 Lomen~ 阅读( ...) 评论( ...) 编辑 收藏

おすすめ

転載: www.cnblogs.com/xzh0717/p/11298284.html