Java中泛型的介紹和使用

  • 2019 年 12 月 2 日
  • 筆記

!今天主要給大家說下Java中泛型的使用以及泛型是什麼?下面請看正文

  • 泛型概述

我們都知道Java里的集合(list,map….)是可以存放任意對象的,只要把對象存儲集合後,那麼這時他們都會被提升成Object類型。當我們在取出每一個對象,並且進行相應的操作,這時必須採用類型轉換。看下面這段示例程式碼

package com.mobaijun;    import java.util.ArrayList;  import java.util.Collection;  import java.util.Iterator;    public class GeneriDemo1{      public static void main(String[] args) {          Collection coll = new ArrayList();          coll.add("mobai");          coll.add("墨白");          coll.add(5);//由於集合沒有做任何限定,任何類型都可以給其中存放          Iterator it = coll.iterator();          while (it.hasNext()) {              //需要列印每個字元串的長度,就要把迭代出來的對象轉成String類型              String str = (String) it.next();              System.out.println(str.length());          }      }  }

我們可以看到控制台列印結果是一個異常,異資訊如下:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

這個Demo在運行時發生了java.lang.ClassCastException,找不到主類或無法載入類。為什麼會發生類型轉換異常呢?我們來分析下:由於集合中什麼類型的元素都可以存儲。導致取出時強轉引發運行時 ClassCastException。怎麼來解決這個問題呢?

Collection雖然可以存儲各種對象,但實際上通常Collection只存儲同一類型對象。例如都是存儲字元串對象。因此 在JDK5之後,新增了泛型(Generic)語法,讓你在設計API時可以指定類或方法支援泛型,這樣的話我們使用API的時候 也變得更為簡潔,並得到了編譯時期的語法檢查。

一句話概述就是:泛型可以在類或方法中預支地使用未知的類型

  • 那麼使用泛型有什麼好處呢?

看下面程式碼體驗一下泛型帶給我們的好處:

package com.mobaijun;    import java.util.ArrayList;  import java.util.Collection;  import java.util.Iterator;    public class GeneriDemo2 {      public static void main(String[] args) {          Collection<String> list = new ArrayList<String>();          list.add("mobai");          list.add("墨白");          // list.add(5);          // 當集合明確類型後,存放類型不一致就會編譯報錯          // 集合已經明確具體存放的元素類型,那麼在使用迭代器的時候,迭代器也同樣會知道具體遍曆元素類型          Iterator<String> it = list.iterator();          while (it.hasNext()) {              String str = it.next();              //當使用Iterator<String>控制元素類型後,就不需要強轉了。獲取到的元素直接就是String類 型              System.out.println(str.length());          }      }  }
  • 泛型的定義與使用

泛型,用來靈活地將數據類型應用到不同的類、方法、介面當中。將數據類型作為參數進行傳遞。

泛型的定義格式:

修飾符 class 類名<代表泛型的變數> {  }

示例程式碼:

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) {      }  }

再例如, ArrayList<Integer> list = new ArrayList<Integer>();

此時,變數E的值就是Integer類型,那麼我們的類型就可以理解為:

class ArrayList<Integer> {      public boolean add(Integer e) {      }      public Integer get(int index) {      }  }
  • 泛型方法

示例程式碼:

public class MyGenericMethod {      public <MVP> void show(MVP mvp) {          System.out.println(mvp.getClass());      }        public <MVP> MVP show2(MVP mvp) {          return mvp;      }  }

在方法調用的時候,明確泛型的類型:程式碼如下

package com.mobaijun;    public class GeneriDemo3 {      public static void main(String[] args) {          MyGenericMethod my = new MyGenericMethod();          my.show("墨白");          my.show(18);          my.show(178.0);      }  }
  • 泛型的介面

示例程式碼:

package com.mobaijun;    public interface MyGenericInterface<E> {      public abstract void add(E e);      public abstract E gitE();  }

下面我們來看下如果要定義一個類該如何使用泛型:

示例程式碼:

package com.mobaijun;    public class MyImpl implements MyGenericInterface<String>{      @Override      public void add(String s) {          // 省略      }        @Override      public String gitE() {          return null;      }  }

在類開始的時候我們以及定義了泛型的類型,那麼這個時候泛型e的值就是String;

  • 如果始終不確定泛型的類型,可以直到創建對象時,確定泛型的類型
package com.mobaijun;    /**   * 不確定泛型的類型   * @param <E>   */  public class MyImpl2<E> implements MyGenericInterface<E> {        @Override      public void add(E e) {        }        @Override      public E gitE() {          return null;      }  }
  • 在創建對象的時候確定泛型的類型
package com.mobaijun;    /**   * 創建對象的時候確定泛型的類型   */  public class GenericInterface  {      public static void main(String[] args) {          MyImpl2<String> my = new MyImpl2<String>();          my.add("墨白");      }  }
  • 泛型還有最後一個知識點,那就是泛型的通配符

當使用泛型類或者介面時,傳遞的數據中,泛型類型不確定,可以通過通配符<?>表示。但是一旦使用泛型的通配符後,只能使用Object類中的共性方法,集合中元素自身方法無法使用。

通配符的基本使用 有如下幾點

泛型的通配符:不知道使用什麼類型來接收的時候,此時可以使用?,?表示未知通配符。

此時只能接受數據,不能往該集合中存儲數據。

示例程式碼:

package com.mobaijun;    import java.util.ArrayList;  import java.util.Collection;    public class MyDemo {      public static void main(String[] args) {          Collection<Integer> c = new ArrayList<Integer>();         getElement(c);           Collection<String> c2 = new ArrayList<String>();         getElement(c2);      }        /**       * 統配符中的?代表著任意類型數據       * 需要注意的是泛型是不存在繼承關係的,       *      Collection<Object> c2 = new ArrayList<String>();錯誤示例       * @param collection       */      public static void getElement(Collection<?> collection){        }  }
  • 通配符高級使用

之前設置泛型的時候,實際上是可以任意設置的,只要是類就可以設置。但是在JAVA的泛型中可以指定一個泛型的上限和下限。

泛型的上限:

格式:類型名稱 <? extends 類 > 對象名稱 意義:只能接收該類型及其子類

泛型的下限:

格式:類型名稱 <? super 類 > 對象名稱 意義:只能接收該類型及其父類型

舉個例子,比如:現已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類

package com.mobaijun;    import java.util.ArrayList;  import java.util.Collection;    public class MyDemo4 {      public static void main(String[] args) {          Collection<Integer> c1 = new ArrayList<Integer>();          Collection<String> c2 = new ArrayList<String>();          Collection<Number> c3 = new ArrayList<Number>();          Collection<Object> c4 = new ArrayList<Object>();            getElementOne(c1);          getElementOne(c2);// 編譯報錯          getElementOne(c3);          getElementOne(c4);// 編譯報錯            getElementTow(c1);// 編譯報錯          getElementTow(c2);// 編譯報錯          getElementTow(c3);          getElementTow(c4);      }      // 泛型的上限:此時的泛型?,必須是Number類型或者Number類型的子類      public static void getElementOne(Collection<? extends Number> collection){}      // 泛型的下限:此時的泛型?,必須是Number類型或者Number類型的父類      public static void getElementTow(Collection<? super Number> collection){}  }

以上就是泛型的全部內容了,如果有幫助到你,請在文末點個在看,祝你有個美好的一天,加油!!!