集合(8):泛型類、泛型方法、泛型接口
前言案例
import java.util.ArrayList;
import java.util.Iterator;
public class GenericDemo1 {
public static void main(String[] args) {
//創建List集合對象
ArrayList list = new ArrayList();
//向集合中添加元素
list.add("hello");
list.add(10);//相當於向上轉型,10 -- int -- Integer
list.add("world");
//獲取迭代器對象
Iterator iterator = list.iterator();
//獲取迭代器對象
while(iterator.hasNext()){
Object next = iterator.next();
String s = (String)next;
System.out.println(s);
}
}
}
執行結果如下:
我們按照正常的寫法,在集合中添加一些不是同類型的數據,在遍歷的時候向下轉型報錯了
ClassCastException:類型轉換異常
為什么呢?
因為我們在存儲數據的時候,存儲了一些String和Integer類型的數據,但是呢,
我們遍歷的時候,默認集合中只存放String類型的數據;但是在存儲數據的時候
沒有告訴我們只能存String類型的數據,如果能在存儲的時候告訴我能存儲哪些數據類型就好了
String[] arr = new String[3];//創建數組的時候明確的元素的類型
arr[0] = "hello";
// arr[1] = 20;當添加int類型的時候是不可行的
java中集合就模仿着數組呢,也有這樣的做法,在創建集合的時候,就明確了元素的數據類型,
創建后,再往集合中加入的元素,只能是定義好的數據類型相關的數據了,然后再向下轉型就沒有問題了。
這樣的技術,java中叫做:泛型
泛型
一、泛型的使用介紹
1、泛型的概述
把明確數據類型的工作,提前到了編譯時期,在創建集合的時候明確數據類型,
這樣的做法有點像把數據類型當作參數一樣進行傳遞。
所以泛型還有一個名字叫做:參數化類型
2、泛型的定義格式
定義格式:
<引用數據類型>,在API中是<E>
注意:尖括號中的數據類型只能是引用數據類型,<E>在創建對象的時候添加在類后面
格式案例:
ArrayList<String> list = new ArrayList<String>();
JDK1.7之后會自動進行類型推斷
所以后面的<String>中的String可加可不加,建議加上
當創建對象的時候加入了泛型,迭代器也要加上泛型
//獲取迭代器對象
Iterator<String> iterator = list.iterator();
在沒使用泛型的時候,添加不同類型元素的時候,不會報錯,在向下轉型的時候才會報錯;
當使用泛型的時候,在添加元素的時候,編寫代碼的時候就會報錯,提前報錯,便於我們更改
3、泛型的好處
添加泛型之后
(1)將我們之前運行時候出現的問題,提前到了編譯時期
(2)不需要強制類型轉換了,而且還可以調用元素類型的方法
(3)優化了代碼,消除不必要的黃色警告線
4、泛型的使用場景
通過觀察API發現,泛型可以出現了類,接口,方法上,看到一些類似與<E>,
一般來說泛型出現在大多使用集合中
二、泛型的應用
1、泛型類
泛型類:把泛型定義在類上(在類名后面添加<變量名>)
格式:public class 類名<泛型類型1,…>
注意:泛型類型必須是引用類型
這里的<>里面的內容僅僅表示的是一種參數數據類型,參數類型是一種變量,
既然是一種變量,就符合變量的命名規則,可以是任意符合標識符起名規則的名字
泛型類的使用
//第1步:定義一個泛型類
class GenericTool1<T> {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
//第2步:泛型類的測試
public class GenericTest1 {
public static void main(String[] args) {
/*
如果前面定義的類不加泛型,默認則是Object類型
GenericTool1 gt1 = new GenericTool1();
添加元素的時候,類型可以是任意的
gt1.setObj("hello");
gt1.setObj(20);
gt1.setObj(12.34);
gt1.setObj(new Student());
*/
//創建泛型類的對象
GenericTool1<String> gt = new GenericTool1<>();
//調用setObj()方法添加元素
gt.setObj("hello");
//gt2.setObj(20);定義過泛型之后,就不能再添加不同類型的元素
//調用getObj()方法獲取元素
String obj = gt.getObj();
System.out.println(obj);
}
}
執行結果如下:
hello
Process finished with exit code 0
2、泛型方法
泛型方法:把泛型定義在方法上
格式:public <泛型類型> 返回類型 方法名(泛型類型 .)
例:
public<T> void show(T t){}
(1)在沒使用泛型的時候,正常寫個類來定義成員方法
//定義一個類
public class GenericTool2 {
public void show(String s){
System.out.println(s);
}
public void show(int i){
System.out.println(i);
}
public void show(double d){
System.out.println(d);
}
}
//定義一個測試類
public class GenericTest2 {
public static void main(String[] args) {
//創建類的對象
GenericTool2 gt1 = new GenericTool2();
//調取類中的show方法,並賦值
gt1.show(10);
gt1.show("hello");
gt1.show(12.34);
}
}
執行結果如下:
10
hello
12.34
Process finished with exit code 0
當我們不使用泛型的時候,在測試類中賦值的時候,必須要根據定義的成員方法參數類型來賦值,
當需要賦值很多類型的時候,需要定義的成員方法也很多,非常的麻煩。
(2)當使用泛型類的時候,泛型類的成員方法參數類型和泛型類一致
賦值很多類型的時候,就不需要定義很多發成員方法了
//定義一個泛型類
class GenericTool2<T> {
//定義成員方法,參數為T類型
public void show(T t){
System.out.println(t);
}
}
//定義一個測試類
public class GenericTest2 {
public static void main(String[] args) {
GenericTool2 gt1 = new GenericTool2();
//前面定義了泛型類,此處再賦值就可以隨便賦值不同的類型了
gt1.show(10);
gt1.show("hello");
gt1.show(12.34);
}
}
執行結果如下:
10
hello
12.34
Process finished with exit code 0
(3)當定義了泛型類,泛型類的成員方法參數類型和泛型類一致,
如果在測試了中創建對象的時候也加上了泛型,會發生什么變化?
//定義一個泛型類
class GenericTool2<T> {
//定義泛型成員方法
public void show(T t){
System.out.println(t);
}
}
//定義一個測試類
public class GenericTest2 {
public static void main(String[] args) {
//創建泛型類對象的時候加上泛型
GenericTool2<String> gt2 = new GenericTool2<>();
gt2.show("hello");
//gt2.show(20);當創建對象的時候加上了泛型,那么賦值int類型就會報錯
//想要賦值int類型的元素,就必須再創建一個int泛型的對象
GenericTool2<Integer> gt3 = new GenericTool2<>();
gt3.show(20);
}
}
執行結果如下:
hello
20
Process finished with exit code 0
由此可見,當定義了泛型類,泛型類的成員方法參數類型和泛型類一致,
在測試了中創建對象的時候也加上了泛型,
賦值不同類型的時候,需要創建很多的對象,就非常的麻煩
如果定義的類上面沒有泛型的話,方法還能不能隨便傳參呢?
答案是可以的,不過這時候就需要用到泛型方法了
而且測試類中創建對象的時候不能有泛型了,不然會報錯
//定義一個類
public class GenericTool2 {
//定義泛型成員方法
public<T> void show(T t){
System.out.println(t);
}
}
//定義一個測試類
public class GenericTest2 {
public static void main(String[] args) {
//創建對象
GenericTool2 gt = new GenericTool2();
//定義泛型方法以后,賦值的時候,可以傳入任意類型的參數
gt.show("hello");
gt.show(20);
gt.show(true);
}
}
執行結果如下:
hello
20
true
Process finished with exit code 0
3、泛型接口
泛型接口:把泛型定義在接口上
格式:public interface 接口名<泛型類型1...>
案例:
//定義泛型接口,接口中的方法參數和接口一致
public interface GenericTool3<T> {
public abstract void show(T t);
}
//定義一個類來實現泛型接口,實現接口的類也要加上泛型
public class GenericTool3Impl<T> implements GenericTool3<T>{
//重寫接口中的抽象方法
@Override
public void show(T t) {
System.out.println(t);
}
}
//泛型接口的測試
public class GenericTest3 {
public static void main(String[] args) {
//接口不能實例化,需要new它的實現類
GenericTool3Impl<String> sgt1 = new GenericTool3Impl<>();
sgt1.show("hello");
}
}
執行結果如下:
hello
Process finished with exit code 0