<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
背景:
從JDK 5.0以後,Java引入了“引數化型別(Parameterized type)”的概念,允許我們在建立集合時再指定集合元素的型別,正如:List ,這表明該List只能儲存字串型別的物件。
解決元素儲存的安全性問題,好比商品、藥品標籤,不會弄錯。
解決獲取資料元素時,需要型別強制轉換的問題,好比不用每回拿商品、藥品都要辨別。
@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 test1(){ ArrayList<String> list = new ArrayList<>(); list.add("AAA"); list.add("BBB"); list.add("FFF"); list.add("EEE"); list.add("CCC"); //遍歷方式一: Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println("-------------"); //便利方式二: for (String str: list) { System.out.println(str); } }
① 集合介面或集合類在JDK 5.0時都修改為帶泛型的結構。
② 在範例化集合類時,可以指明具體的泛型型別
③ 指明完以後,在集合類或介面中凡是定義類或介面時,內部結構(比如:方法、構造器、屬性等)使用到類的泛型的位置,都指定為範例化的泛型型別。
比如:add(E e) —>範例化以後:add(Integer e)
④ 注意點:泛型的型別必須是類,不能是基本資料型別。需要用到基本資料型別的位置,拿包裝類替換
⑤ 如果範例化時,沒有指明泛型的型別。預設型別為 java.lang.Object 型別
說明
1.泛型類可能有多個引數,此時應將多個引數一起放在尖括號內。比如<E1,E2,E3>
2.泛型類的構造器如下: public GenericClass(){}
而下面是錯誤的: public GenericClass<E>{}
3.範例化後,操作原來泛型位置的結構必須與指定的泛型型別一致。
4.泛型不同的參照不能相互賦值。
儘管在編譯時 ArrayList和ArrayList是兩種型別,但是,在執行時只有一個ArrayList被載入到JVM中。
5.泛型如果不指定,將被擦除,泛型對應的型別均按照Object處理,但不等價於Object。
建議:泛型要使用一路都用。要不用,一路都不要用。
6.如果泛型結構是一個介面或抽象類,則不可建立泛型類的物件。
7.JDK 7.0,泛型的簡化操作: ArrayList<Fruit>first= new ArrayList<>();(型別推斷)
8.泛型的指定中不能使用基本資料型別,可以使用包裝類替換。
9.在類/介面上宣告的泛型,在本類或本介面中即代表某種型別,可以作為非靜態屬性的型別、非靜態方法的引數型別、非靜態方法的返回值型別。但在靜態方法中不能使用類的泛型。
10.異常類不能是泛型的。
11.不能使用 new E[]。但是可以:E[] elements= (E[])new Object[capacity];
參考:ArrayList原始碼中宣告:Object[] elementData,而非泛型引數型別陣列。
12.父類別有泛型,子類可以選擇保留泛型也可以選擇指定泛型型別
子類不保留父類別的泛型:按需實現
子類保留父類別的泛型:泛型子類
結論:子類必須是“富二代”,子類除了指定或保留父類別的泛型,還可以增加自己的泛型
泛型類、泛型介面、泛型方法
泛型的宣告
interface List<T> 和 class GenTest<K,V> 其中,T,K,V,不代表值,而是表示型別。這裡使用任意字母都可以。
常用T表示,是Type的縮寫。
泛型的範例化
一定要在類名後面指定型別引數的值(型別)。如:
List<String> strList =new ArrayList<String>(); Iterator<Customer> iterator = customers.iterator();
T只能是類,不能用基本資料型別填充。但可以使用包裝類填充
把一個集合中的內容限制為一個特定的資料型別,這就是 generics背後的核心思想
//JDK 5.0以前 Comparable c = new Date(); System.out.println(c.comparaTo("red"); //JDK 5.0以後 Comparable <Date> c = new Date(); System.out.println(c.comparaTo("red");
自定義泛型類
程式碼範例:
/** * 自定義泛型類Order */ class Order<T> { private String orderName; private int orderId; //使用T型別定義變數 private T orderT; public Order() { } //使用T型別定義構造器 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); // } // //try-catch中不能是泛型的。 // public void show(){ // try { // // }catch (T t){ // // } // } //泛型方法:在方法中出現了泛型的結構,泛型引數與類的泛型引數沒有任何關係。 //換句話說,泛型方法所屬的類是不是泛型類都沒有關係。 //泛型方法,可以宣告為靜態的。 // 原因:泛型引數是在呼叫方法時確定的。並非在範例化類時確定。 public static <E> List<E> copyFromArryToList(E[] arr) { ArrayList<E> list = new ArrayList<>(); for (E e : list) { list.add(e); } return list; } }
自定義泛型介面
程式碼範例:
/** * 自定義泛型介面 */ public interface DemoInterface <T> { void show(); int size(); } //實現泛型介面 public class Demo implements DemoInterface { @Override public void show() { System.out.println("hello"); } @Override public int size() { return 0; } } @Test //測試泛型介面 public void test3(){ Demo demo = new Demo(); demo.show(); }
自定義泛型方法
方法,也可以被泛型化,不管此時定義在其中的類是不是泛型類。在泛型方法中可以定義泛型引數,此時,引數的型別就是傳入資料的型別。
泛型方法的格式: [存取許可權]<泛型>返回型別 方法名(泛型標識 引數名稱])丟擲的異常
泛型方法宣告泛型時也可以指定上限
泛型方法宣告泛型時也可以指定上限
程式碼範例:
//泛型方法:在方法中出現了泛型的結構,泛型引數與類的泛型引數沒有任何關係。 //換句話說,泛型方法所屬的類是不是泛型類都沒有關係。 //泛型方法,可以宣告為靜態的。 // 原因:泛型引數是在呼叫方法時確定的。並非在範例化類時確定。 public static <E> List<E> copyFromArryToList(E[] arr) { ArrayList<E> list = new ArrayList<>(); for (E e : list) { list.add(e); } return list; }
1.萬用字元的使用
使用型別萬用字元:?
比如:List<?>,Map<?,?>
List<?> 是 List<String>、List<Object> 等各種泛型 List 的父類別。
讀取 List<?> 的物件list中的元素時,永遠是安全的,因為不管list的真實型別是什麼,它包含的都是Object
寫入list中的元素時,不可以。因為我們不知道c的元素型別,我們不能向其中新增物件。 除了新增null之外。
說明:
將任意元素加入到其中不是型別安全的
Collection<?> c = new ArrayList<String>()
c.add(new Object());//編譯時錯誤
因為我們不知道c的元素型別,我們不能向其中新增物件。add 方法有型別引數 E 作為集合的元素型別。我們傳給add的任何引數都必須是一個已知型別的子類。因為我們不知道那是什麼型別,所以我們無法傳任何東西進去。
唯一的例外的是 null,它是所有型別的成員。
我們可以呼叫 get() 方法並使用其返回值。返回值是一個未知的型別,但是我們知道,它總是一個Object。
程式碼範例:
@Test public void test3(){ List<Object> list1 = null; List<String> list2 = null; List<?> list = null; list = list1; list = list2; //編譯通過 // print(list1); // print(list2); // List<String> list3 = new ArrayList<>(); list3.add("AA"); list3.add("BB"); list3.add("CC"); list = list3; //新增(寫入):對於List<?>就不能向其內部新增資料。 //除了新增null之外。 // list.add("DD"); // list.add('?'); list.add(null); //獲取(讀取):允許讀取資料,讀取的資料型別為Object。 Object o = list.get(0); System.out.println(o); } public void print(List<?> list){ Iterator<?> iterator = list.iterator(); while(iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } }
//注意點1:編譯錯誤:不能用在泛型方法宣告上,返回值型別前面<>不能使用? public static <?> void test(ArrayList<?> list){ } //注意點2:編譯錯誤:不能用在泛型類的宣告上 class GenericTypeClass<?>{ } //注意點3:編譯錯誤:不能用在建立物件上,右邊屬於建立集合物件 ArrayList<> list2 new ArrayList<?>();
1.<?>:允許所有泛型的參照呼叫
2.萬用字元指定上限
上限 extends:使用時指定的型別必須是繼承某個類,或者實現某個介面,即 <=
3.萬用字元指定下限
下限 super:使用時指定的型別不能小於操作的類,即 >=
4.舉例:
<?extends Number>(無窮小, Number]
只允許泛型為Number及Number子類的參照呼叫
<?super Number>[Number,無窮大)
只允許泛型為Number及Number父類別的參照呼叫
<? extends Comparable>
只允許泛型為實現 Comparable介面的實現類的參照呼叫
程式碼範例:
@Test public void test4(){ List<? extends Person> list1 = null; List<? super Person> list2 = null; List<Student> list3 = new ArrayList<Student>(); List<Person> list4 = new ArrayList<Person>(); List<Object> list5 = new ArrayList<Object>(); list1 = list3; list1 = list4; // list1 = list5; // list2 = list3; list2 = list4; list2 = list5; //讀取資料: list1 = list3; Person p = list1.get(0); //編譯不通過 //Student s = list1.get(0); list2 = list4; Object obj = list2.get(0); 編譯不通過 // Person obj = list2.get(0); //寫入資料: //編譯不通過 // list1.add(new Student()); //編譯通過 list2.add(new Person()); list2.add(new Student()); }
到此這篇關於Java知識梳理之泛型用法詳解的文章就介紹到這了,更多相關Java泛型內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45