java 基礎(泛型)
阿新 • • 發佈:2021-10-10
什麼是泛型
集合容器類在設計階段/宣告階段不能確定這個容器到底實際存的是什麼型別的物件,所以在 JDK1.5 之前只能把元素型別設計為 Object,JDK1.5 之後使用泛型來解決。因為這個時候除了元素的型別不確定,其他的部分是確定的,例如關於這個元素如何儲存,如何管理等是確定的,因此此時把元素的型別設計成一個引數,這個型別引數叫做泛型。Collection
泛型的概念
- 所謂泛型,就是允許在定義類、介面時通過一個標識表示類中某個屬性的型別或者是某個方法的返回值及引數型別。這個型別引數將在使用時(例如,繼承或實現這個介面,用這個型別宣告變數、建立物件時)確定(即傳入實際的型別引數,也稱為型別實參)。I
- 從JDK1.5以後,Java引入了“引數化型別( Parameterized type)”的概念,允許我們在建立集合時再指定集合元素的型別,正如:List
,這表明該List只能儲存字串型別的物件。 - JDK1.5 改寫了集合框架中的全部介面和類,為這些介面、類增加了泛型支援,從而可以在宣告集合變數、建立集合物件時傳入型別實參。
泛型的使用
在集合中使用泛型總結:
- 集合介面或集合類在 jdk5.0 時都修改為帶泛型的結構。
- 在例項化集合類時,可以指明具體的泛型型別
- 指明完以後,在集合類或介面中凡是定義類或介面時,內部結構(比如:方法、構造器,屬性等)使用到類的泛型的位置,都指定為例項化的泛型型別。
比如:add(E e) --->例項化以後:add(Integer e) - 注意點:泛型的型別必須是類,不能是基本資料型別。需要用到基本資料型別的位置,拿包裝類替換
- 如果例項化時,沒有指明泛型的型別。預設型別為 java.lang.object型別。
自定義泛型結構:泛型類,泛型介面
- 泛型類可能有多個引數,此時應將多個引數一起放在尖括號內。比如:<E1,E2,E3>
- 泛型類的構造器如下: public GenericClass(){}。
而下面是錯誤的: public GenericClass(){} - 例項化後,操作原來泛型位置的結構必須與指定的泛型型別一致。
- 泛型不同的引用不能相互賦值。
儘管在編譯時ArrayList和ArrayList 是兩種型別,但是,在執行時只有一個ArrayList被載入到JVM中。 - 泛型如果不指定,將被擦除,泛型對應的型別均按照Object處理,但不等價於Object。經驗:泛型要使用一路都用。要不用,一路都不要用。
- 如果泛型類是一個介面或抽象類,則不可建立泛型類的物件。
- jdk1.7,泛型的簡化操作:ArrayList
flist = new ArrayList<>(); - 泛型的指定中不能使用基本資料型別,可以使用包裝類替換。
- 在類/介面上宣告的泛型,在本類或本介面中即代表某種型別,可以作為非靜態屬性的型別。非靜態方法的引數型別、非靜態方法的返回值型別。但在靜態方法中不能使用類的泛型。
- 異常類不能是泛型的
- 不能使用new E[]。但是可以:E[] elements =(E[])new Object[capacity];
參考: ArrayList原始碼中宣告:Object[] elementData,而非泛型引數型別陣列。 - 父類有泛型,子類可以選擇保留泛型也可以選擇指定泛型型別:
子類不保留父類的泛型:按需實現沒有型別擦除
具體型別
子類保留父類的泛型:泛型子類
全部保留
部分保留
結論:子類必須是“富二代”,子類除了指定或保留父類的泛型,還可以增加自己的泛型
GenericTest.java
package com.klvchen.java;
import org.junit.Test;
import java.util.*;
public class GenericTest {
@Test
public void test1(){
ArrayList list = new ArrayList();
//需求: 存放學生的成績
list.add(78);
list.add(76);
list.add(89);
list.add(88);
//問題一:型別不安全
list.add("Tom");
for (Object score : list) {
//問題二:強轉時,可能出現CLasscastException
int stuScore = (Integer) score;
System.out.println(stuScore);
}
}
// 在集合中使用泛型的情況: 以 Arraylist 為例子
@Test
public void test2() {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(78);
list.add(76);
list.add(89);
list.add(88);
// 編譯時,就會進行型別檢查,保證資料的安全
//list.add( "Tom");
//方式一
//for (Integer score : list) {
// //避免了強轉操作
// int stuScore = score;
// System.out.println(stuScore);
//}
//方式二
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
int stuScore = iterator.next();
System.out.println(stuScore);
}
}
// 在集合中使用泛型的情況: 以 HashMap 為例子
@Test
public void test3(){
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 87);
map.put("Jerry", 77);
map.put("Jack", 67);
//泛型的巢狀
Set<Map.Entry<String, Integer>> entry = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> e = iterator.next();
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key + " ----> " + value);
}
}
}
GenericTest1.java
package com.klvchen.java;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class GenericTest1 {
@Test
public void test1(){
//如果定義了泛型類,例項化沒有指明類的泛型,則認為此泛型型別為object型別
//要求:如果大家定義了類是帶泛型的,建議在例項化時要指明類的泛型。
Order order = new Order();
order.setOrderT(123);
order.setOrderT("ABC");
//建議:例項化時指明類的泛型
Order<String> order1 = new Order<>("orderAA", 1001, "Order:AA");
order1.setOrderT("AA:hello");
}
@Test
public void test2(){
SubOrder sub1 = new SubOrder();
//由於子類在繼承帶泛型的父類時,指明瞭泛型型別。則例項化子類物件時,不再需要指明泛型。
sub1.setOrderT(1122);
SubOrder1<String> sub2 = new SubOrder1<>();
sub2.setOrderT("order2...");
}
@Test
public void test3(){
ArrayList<String> list1 = null;
ArrayList<Integer> list2 = null;
//泛型不同的引用不能相互賦值
//list1 = list2;
Person p1 = null;
Person p2 = null;
p1 = p2;
}
@Test
public void test4(){
Order<String> order = new Order<>();
Integer[] arr = new Integer[]{1, 2, 3, 4};
//泛型方法在呼叫時,指明泛型引數的型別。
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);
}
}
Order.java
package com.klvchen.java;
import java.util.ArrayList;
import java.util.List;
public class Order<T> {
String orderName;
int orderId;
//類的內部結構就可以使用類的泛型
T orderT;
public Order() {
//編譯不通過
//T[] arr = new T[10];
T[] arr = (T[]) new Order[10];
}
public Order(String orderName, int orderId, T orderT) {
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
//如下的三個方法都不是泛型方法
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
//靜態方法中不能使用類的泛型
//public static void show(T orderT) {
// System.out.println(orderT);
//}
// 泛型方法:在方法中出現了泛型的結構,泛型引數與類的泛型引數沒有任何關係。
// 換句話說,泛型方法所屬的類是不是泛型類都沒有關係。
// 泛型方法,可以宣告為靜態的。原因: 泛型引數是在呼叫方法時確定的。並非在例項化類時確定。
public static <E> List<E> copyFromArrayToList(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for (E e : arr) {
list.add(e);
}
return list;
}
}
Person.java
package com.klvchen.java;
public class Person {
}
SubOrder.java
package com.klvchen.java;
public class SubOrder extends Order<Integer> {//SubOrder:不是泛型類
}
SubOrder1.java
package com.klvchen.java;
public class SubOrder1<T> extends Order<T>{ //SubOrder1<T>:仍然是泛型類
}