泛型方法的定义和使用_泛型( Generic )
泛型(Generic)
1. 泛型概述
- 泛型是一個未知的, 不確定的數據類型. 比如ArrayList 中的E, 就是一個未知的不確定的數據類型, 那么他就是一個泛型
- 泛型雖然是一個未知的, 不確定的數據類型, 但他不是一直未知, 一直不確定當我們使用這個類的時候, 會指定這個泛型的類型. 比如ArrayList , ArrayList
- 泛型可以省略, 如果泛型省略, 相當于泛型是Object. 如ArrayLIst list = new ArrayList();這樣的話就可以放任何類型的數據.
- 泛型也是語法糖, 下面會用例子介紹
前面曾提過, 集合中是可以存放任意對象的, 只要把對象儲存集合后, 那么這是他們都會被提升成Object類型. 當我們在取出每一個對象, 并進行相應的操作, 必須==采用類型轉換==.
看一段代碼:
import java.util.Iterator;public class GenericTest {public static void main(String[] args) {Collection coll = new ArrayList();coll.add("搗亂黃");coll.add("搗亂綠");coll.add(5);//由于集合并沒有限定,所以任何類型都可以給其中存放Iterator it = coll.iterator();while (it.hasNext()){//需要打印每個字符串的長度, 就要把迭代出來的對象轉成String類型String str =(String) it.next();System.out.println(str.length());}} }//3 //3 //Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap') // at drafts.drafts3.GenericTest.main(GenericTest.java:16)程序在運行時拋出了java.lang.ClassCastException.類型轉換異常
為什么會出現此異常呢?
由于集合中什么類型都可以儲存, 導致取出時強制轉換, 引發運行時ClassCastException.
Collection雖然可以儲存各種對象, 但實際上, 通常Collection只儲存同一類型對象, 因此, 在JDK1.5后, 新增了泛型(Generic)語法
使得在設計API時可以指定類或方法支持泛型, 這樣我們使用API的時候也變得更為簡潔, 并得到了==編譯時運行檢查==.
- 泛型 : 可以在類或方法中預支的使用未知的類型,
2. 泛型的好處
看下面一段代碼: 體現了省去向下轉型
package drafts.drafts4;import java.util.ArrayList; import java.util.Collection; import java.util.Iterator;public class GenericTest2 {public static void main(String[] args) {Collection <String> list = new ArrayList<>();list.add("搗亂黃");list.add("搗亂綠");//list.add(666); 這時, 不是String類型的元素就會編譯報錯Iterator<String> it = list.iterator();while (it.hasNext()){String str = it.next();//當使用Iterator<String>控制元素類型后, 就不需要強轉了, //獲取到的元素就是String類型System.out.println(str.length());}} }tips: 泛型時數據類型的一部分, 我們將類名與泛型合并一起看做數據類型泛型擦除: 泛型也是語法糖, 本質還是要做向下轉型.
Java中的泛型都是偽泛型, 泛型只在源代碼階段有效, 一旦編譯, 泛型就會消失, 俗稱泛型參數
package drafts.drafts10; import java.util.ArrayList; /*泛型擦除, 在用xjad反編譯.class文件后發現Java中的泛型都是偽泛型, 泛型只在源代碼階段有效, 一旦編譯, 泛型就會消失, 俗稱泛型擦除*/ @SuppressWarnings("all") public class GenericTest2 {public static void main(String[] args) {ArrayList<String> list2 = new ArrayList<>();//list2.add(100);編譯時期報錯list2.add("hello");list2.add("world");list2.add("java");for (String str : list2) {System.out.println(str.length());} //編譯之后泛型就沒了, 本質其實還是向下轉型} }3. 泛型的定義與使用
? 泛型, 是一種未知的不確定的數據類型. 用來靈活的將數據類型應用到不同的類, 方法, 接口中. 將數據類型作為參數進行傳遞.
? 如果定義類的時候, 在類名后面加上, 此時就表示定義了一個未知的, 不確定的數據類型T , 這個T就是一個泛型, T可以用任何字母代替, 但一般用T (type)
這個位置的數據類型T會在我們使用這個類的時候確定下來
?
### 3.1 含有泛型的類( 泛型類 )
定義格式 :
修飾符 class 類名 <代表泛型的變量> { }例如, API中的ArrayList集合class ArrayList<E>{public boolean add (E e) {}public E get (int index) {}... }在類中定義的泛型在整個類中都可以使用
泛型在定義的時候不具體, 使用的時候才具體, 在使用的時候確定泛型的具體數據類型
在創建對象的時候確定泛型 :
例如, ArrayList<String> list = new ArrayList<String> ();
此時, 變量E的值就是String類型. 那么我們的類型就可以理解為 :
class ArrayList<String>{public boolean add (String e) {}public String get (int index) {}... }3.2 含有泛型的方法
? 如果想要延后泛型類型的確認時間, 那么可以使用泛型方法. 如果將泛型定義在方法上, 那么該方法就是一個泛型方法
? 在方法上定義的泛型, 需要調用方法的時候才能夠確定這個泛型是什么類型
定義格式 :
修飾符 <代表泛型的變量> 返回值類型 方法名 (參數列表) { ... }例如 :
public class MyGenericMethod {public <E> void show <E e> {System.out.println(mvp.getClass());}public <E> E show2 (E e) {return e;} }調用方法時, 確定泛型的類型
public class GenericMethodDemo {public static void main (String[] args){//創建對象MyGenericMethod mm = new MyGenericMethod();mm.show("aaa"); //class java.lang.Stringmm.show(1234); //class java.lang.Integermm.show(12.211); //class java.lang.Double} }定義方法, 接收什么參數, 就返回什么結果
: 表示在方法上定義了一個不確定的數據類型E
后面兩個E: 使用泛型當做參數和返回值的數據類型
在方法上定義的泛型, 可以在整個方法中使用
在方法上定義的泛型, 需要調用這個方法的時候才能確定這個泛型表示的是什么類型.
public <E> E getSame(E e) {return e ; }小結 :
如果在類上面定義泛型, 那么類就是泛型類, 在類上面定義的泛型, 可以在整個類中使用, 類上面定義的泛型需要使用整個類的時候才能確定泛型的類型
如果在方法上面定義泛型, 那么這個方法就是泛型方法, 在方法上面定義的泛型, 可以在整個方法中使用, 方法上面定義的泛型需要使用該方法的時候才能確定泛型的類型
3.3 含有泛型的接口
如果在定義接口的時候在接口名后面加上尖括號, 那么這個接口就是一個泛型接口, 在接口中定義的泛型, 在整個接口中都可以使用.
定義格式 :
修飾符 interface 接口名<代表泛型的變量> {...}例如 :
public interface MyInterface <T> {//表示定義了一個不確定的數據類型Tpublic abstract void add (E e);public abstract void E getE(); }使用格式 :
3.3.1 定義類的時候確定泛型的類型
例如
public class MyImp1 implements MyGenericInterface<String> {@Overridepublic void add(String e) {// 省略...}@Overridepublic String getE() {return null;} }此時, 泛型E 的值就是String類型
3.3.2 直到創建對象時, 才確定泛型的類型
例如
public class MyImp2<E> implements MyGenericInterface<E> {@Overridepublic void add(E e) {// 省略...}@Overridepublic E getE() {return null;} }確定泛型 :
/* * 使用 */ public class GenericInterface {public static void main(String[] args) {MyImp2<String> my = new MyImp2<String>(); my.add("aa");} }泛型接口的使用:
3.4 泛型通配符
泛型之間是沒有繼承關系的, 比如ArrayList并不是ArrayList的父類
如果想要讓泛型可以匹配任何類型的數據, 那么可以使用泛型通配符.
我們用?表示泛型通配符.
==注意 :== 泛型通配符要使用在參數位置==被動匹配==, 不能主動使用.
3.4.1 泛型通配符的使用
import java.util.ArrayList; /* 泛型之間是沒有繼承關系的。比如ArrayList<Object>并不是ArrayList<String>的父類。 如果想要讓泛型可以匹配任何類型的數據,那么可以使用泛型通配符。 ? 表示泛型通配符,可以匹配任何類型的泛型。 注意: 泛型通配符要使用在參數位置被動匹配, 不能主動使用。 */ public class Demo01Generic { public static void main(String[] args) { //創建集合,用來保存字符串 ArrayList<String> strList = new ArrayList<>(); //添加元素 strList.add("Hello"); strList.add("World"); strList.add("Java"); //調用printArrayList方法,遍歷集合 printArrayList(strList); //創建集合,保存Integer ArrayList<Integer> intList = new ArrayList<>(); //調用printArrayList,遍歷 printArrayList(intList); //創建集合,使用?當做泛型類型 //ArrayList<?> list = new ArrayList<>(); //list.add(); } /* 定義一個方法,用來遍歷存儲任何類型數據的集合。 參數: ArrayList<Object> */ public static void printArrayList(ArrayList<?> list) { //?表示泛型通配符,可以匹配任何類型的泛型。 //對參數list集合進行遍歷 for (Object obj : list) { System.out.println(obj); } } }
3.4.2 泛型限定
如果想要對?泛型通配符的使用范圍進行限制,那么可以使用泛型限定(上限,下限)
? <? extends A>:泛型類型要么是A類,要么是A類的子類, 孫子類...。 上限。 ? <? super A>: 泛型類型要么是A類,要么是A類的父類, 爺爺類 直到Object類。 下限。
? 泛型主要用于代碼的重構.
示例:
import java.util.ArrayList; /* 如果想要對?泛型通配符的使用范圍進行限制,那么可以使用泛型限定(上限,下限) <? extends A>:泛型類型要么是A類,要么是A類的子類。 上限。 <? super A>: 泛型類型要么是A類,要么是A類的父類。 下限。 泛型主要用于代碼的重構. */ public class Demo02Generic { public static void main(String[] args) { //創建集合 ArrayList<Student> stuList = new ArrayList<>(); //添加元素 stuList.add(new Student("jack", 20)); stuList.add(new Student("rose", 12)); stuList.add(new Student("tony", 24)); //調用printArrayList方法 printArrayList(stuList); //創建集合 ArrayList<Person> personList = new ArrayList<>(); printArrayList(personList); //創建集合 ArrayList<Object> objList = new ArrayList<>(); //printArrayList(objList); 要求泛型要么是Person,要么是Person的子類,不能是Person的父類 //method(stuList); 泛型類型要么是Person,要么是Person的父類,不能是Person的子類 method(personList); method(objList); } /* 定義方法,使用集合當做參數。 */ public static void method(ArrayList<? super Person> list) { //泛型類型要么是Person,要么是Person的父類 } /* 要求:定義方法,遍歷保存Person或者Person子類對象的集合。 */ public static void printArrayList(ArrayList<? extends Person> list) {//泛型的類型要么是Person,要么是Person的子類 for (Person p : list) { System.out.println(p); } } }
總結
以上是生活随笔為你收集整理的泛型方法的定义和使用_泛型( Generic )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用python做公众号网页_Python
- 下一篇: 德之杰DSC-630相机试用