91精品新拍在线观看,91精品一区二区,91精品一区二区三区久久久久,91精品在线播放,91精品中综合久久久久婷婷

<pre id="fhfjj"><ruby id="fhfjj"><var id="fhfjj"></var></ruby></pre>
    <p id="fhfjj"><del id="fhfjj"></del></p>

    <p id="fhfjj"><mark id="fhfjj"><progress id="fhfjj"></progress></mark></p>

      當前位置: 首頁 / 技術分享 / 正文
      民哥帶你快速精通java泛型(一)

      2022-10-18

      泛型 類型   

        泛型由入門到精通

        Hi,小伙伴你好~歡迎進入泛型的學習,在學習之前友情提醒一下:學習泛型需要小伙伴們具備一定的javaSE基礎,如果之前小伙伴們沒有接觸過java,大家可以移步到千鋒北京java好程序員的javaSE課程進行學習。

        在正式開始學習之前,我們先來看一段經常書寫的代碼,分析一下代碼存在那些問題?

        代碼如下:

      public class GenericsDemo {
      public static void main(String[] args) {
      //1.創建一個List對象
      List list = new ArrayList();
      //2.向List中添加數據
      list.add("python");
      list.add("java");
      list.add(66);
      //3.遍歷集合
      for (int i = 0; i <list.size() ; i++) {
      //4.把集合中的每個元素轉成String類型
      String ele = (String) list.get(i);
      //5.打印-測試結果
      System.out.println("元素的值:"+ele);
      }
      }
      }

        運行代碼,會報如下圖的異常:

      a1

        那么小伙們,我們來分析一下原因,到底是因為什么報這個異常呢?

        在代碼中我們定義了一個List類型的集合,先向其中加入了兩個String類型的值,隨后加入一個Integer類型的值。這是完全允許的,因為此時list默認的類型為Object類型,所以在代碼編譯期間沒有任何問題。

        但是在運行代碼時,由于list集合中既有String類型的值,又有Integer類型的值,致使list集合無法區分值是什么類型,很容易出現上圖中的錯誤。因為編譯階段正常,而運行時會出現“java.lang.ClassCastException”異常。因此導致此類錯誤編碼過程中不易發現。

        分析完了,小伙們現在明白了吧,通過分析我們發現上述代碼主要存在兩個問題:

        當我們將數據存入集合時,集合不會記住數據的類型,默認數據類型都是Object。

        當我們遍歷集合中的數據時,人為進行強制類型轉換,很容易報“java.lang.ClassCastException”。強制類型轉換異常

        那么有沒有什么辦法可以使集合能夠記住集合內元素各類型,且能夠達到只要編譯時不出現問題,運行時就

        不會出現“java.lang.ClassCastException”異常呢?

        答案就是使用泛型。

        那么什么是泛型呢?

        第一關 讓我們一起走入泛型

        1.泛型的概述

        1.1 什么是泛型

        泛型,泛指任意類型,可以應用在接口上,類上,變量上,方法上,以及方法的參數中。

        百度百科介紹:

        泛型是jdk1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口、泛型方法。

        在jdk1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實現參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。對于強制類型轉換錯誤的情況 ,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。

        泛型的好處:使用泛型,首先可以通過IDE進行代碼類型初步檢查,然后在編譯階段進行編譯類型檢查,以保證類型轉換的安全性;并且所有的強制轉換都是自動和隱式的,可以提高代碼的重用率。

        個人理解:

        簡單來說:泛型,即“參數化類型”,那么類型“參數化”到底怎么理解呢?

        顧名思義,類型“參數化”就是將類型由原來的具體類型,變成參數化的“類型”,有點類似于方法中的變量參數,不過此時是類型定義成參數形式(你可以理解為類型形參),然后在使用時傳入具體的類型(也就是類型實參)。為什么這樣操作呢?因為它能讓類型"參數化",也就是在不創建新的類型的情況下,通過泛型可以指定不同類型來控制形參具體限制的類型。

        總結:

        泛型介紹完了, 小伙伴看完上述解釋后,能理解泛型是什么了嗎?我們可以用兩句話來概括一下:

        泛型在聲明時,用標記符表示,僅僅作為“參數化的類型”,可以理解為形式參數。

        比如:

        //定義List集合時,用標記符E表示任意類型,E可以理解為形式參數,沒有具體的類型值public interface Listextends Collection{ ----------}

        泛型在使用時,需要指定具體的類型,也就是類型實際的參數。

        比如:

        //在使用List集合時,需要確定E的具體類型,String可以理解為具體的類型,也就是實際的參數值Listlist = new ArrayList();

        1.2 常用的泛型標記符

        E - Element (集合使用,因集合中存放元素)

        T - Type(Java 類)

        K - Key(鍵) V - Value(值)

        N - Number(數值類型)

        ? - 表示不確定的java類型

        S、U、V - 2nd、3rd、4th types

        你可能會有疑問,弄這么多標識符干嘛,直接使用萬能的Object難道不香么?我們知道Object是所有類的基類(任何類如果沒有指明其繼承類,都默認繼承于Object類),因此任何類的對象都可以設置Object的引用,只不過在使用的時候可能要類型強制轉換。但是如果設置了泛型E、T等這些標識符,那么在實際使用之前類型就已經確定,因此不再需要類型強制轉換

        2.泛型的語法使用

        2.1 泛型在集合中的使用

        單列集合中List中

      public interface List<E> extends Collection<E> {
      ----
      <T> T[] toArray(T[] a);
      ----
      }

        雙列集合Map中

      public class HashMap<K,V> extends AbstractMap<K,V>
      implements Map<K,V>, Cloneable, Serializable {
      ---
      V get(Object key){---};
      V put(K key, V value){---};
      V remove(Object key){---};
      void putAll(Map<? extends K, ? extends V> m){---};
      -----
      }

        小伙們可以看到:List,HashMap的源碼,在聲明集合時或者定義方法時,使用采用尖括號內加占位符的形式 ,這里的占位符就是我們上面說的泛型標記符,泛型標記符號E,K,V,T等用來表示任意類型(E,K,V,T也就是“泛型形參”,在實例化集合對象時需要明確的具體的類型(也就是“泛型的實際參數”))。

        通過觀察集合的源碼,那么我們自己也可以定義泛型接口,泛型類以及泛型方法,下面我們一起操作一下吧。

        2.2 聲明泛型接口

        泛型應用于接口。例如生成器(GeneratorType),這是一種專門負責創建對象的類。當使用生成器創建新的對象時,它不需要任何參數,也就是說生成器無需額外的信息就知道如何創建新對象。

        一般而言,一個生成器只定義一個方法,該方法用以產生新的對象。

      /**
      * 定義一個泛型接口:生成任意對象
      * @param <T>: 泛型形式參數,可以是任意類型
      */
      public interface GeneratorType<T> {
      T create();
      }

      /**
      * 測試泛型接口
      */
      class DemoGeneratorType{
      public static void main(String[] args) {
      //1.使用生成器:創建random對象
      GeneratorType<Random> gt= new GeneratorType<Random>() {
      @Override
      public Random create() {
      return new Random();
      }
      };
      //2.使用 GeneratorType:創建對象
      Random random = gt.create();
      }
      }

        來,小伙伴們,我們一起分析下上面的代碼:

        我們聲明了一個泛型接口 GeneratorType,目的用來生成任意類型的對象,在這里T可以表示任意類型。

        我們在測試類中,通過GeneratorType創建對象時,可以傳遞任意類型。

        比如 GeneratorType,那么就可以生成Random對象了

        注意: 在這里,我們通過匿名內部類的方式創建了Random對象,這種寫法大家要慢慢熟悉喔。

        2.3 聲明泛型類

        泛型應用于類上面。例如訂單類(Order),這是一個專門負責封裝訂單里面商品的類,當我們購物生成訂單時,訂單里面可以包含任何商品信息。

        請注意,在類上定義的泛型,在類的變量、方法的參數以及方法中同樣也能使用(靜態方法除外)。

      /**
      * 定義一個訂單類:封裝任意類型的商品信息
      * @param <T>
      */
      public class Order<T> {
      private T t ;//在變量中使用: T表示任意商品類型
      public T get(){//在普通方法中使用:T表示任意商品類型
      return t;
      }
      public void set(T t){//在方法的參數使用: T表示任意類型
      this.t = t;
      }
      //測試:
      public static void main(String[] args) {
      Order<Phone> order = new Order<Phone>();//創建訂單對象:封裝Phone商品
      order.set(new Phone("華為Mate20",3899.0));
      System.out.println("商品名稱:"+order.get().getPhoneName());
      }
      }
      //定義手機商品類
      class Phone{
      private String phoneName;
      private Double phonePrice;

      public Phone(String phoneName, Double phonePrice) {
      this.phoneName = phoneName;
      this.phonePrice = phonePrice;
      }

      public Phone() {
      }

      public String getPhoneName() {
      return phoneName;
      }

      public void setPhoneName(String phoneName) {
      this.phoneName = phoneName;
      }

      public Double getPhonePrice() {
      return phonePrice;
      }

      public void setPhonePrice(Double phonePrice) {
      this.phonePrice = phonePrice;
      }
      }

        ok,泛型類我們聲明完成了,大家看一下是不是和我們聲明泛型接口很相似啊,確實是一樣的。

        聲明的語法就是:類名,在這里T可以表示任意類型。

        小伙伴也可以看到,我們定義了一個帶泛型的Order類,在我們創建訂單對象時,可以傳入任意類型的商品對象,使我們的操作更加靈活

        2.4 聲明泛型方法

        泛型應用于方法上面。前面說過在泛型類上定義的泛型,在類的方法中也能使用(靜態方法除外)。但是有的時候我們只想在某個方法上使用泛型,而不是整個類,這也是被允許的,下面我和小伙們一起來體驗一下。

        比如FactoryBean工廠類,通過泛型方法,創建任意類型的對象。

      package cn.qf;
      /**
      * 定義一個工廠Bean:
      */
      public class FactoryBean {
      /*
      定義不帶泛型的方法
      */
      public static Object createObject0(String className) throws Exception{
      return Class.forName(className).newInstance();
      }
      /*
      定義一個普通的泛型方法:className表示類的全路徑
      */
      public <T> T createObject1(String className) throws Exception{
      return (T) Class.forName(className).newInstance();
      }
      /*
      定義一個靜態的泛型方法:className表示類的全路徑
      */
      public static <T> T createObject2(String className)throws Exception{
      return (E) Class.forName(className).newInstance();
      }
      //測試:
      public static void main(String[] args) throws Exception {
      //創建一個Phone對象 : 不使用泛型方法,需要類型強轉
      Phone p1 = (Phone) FactoryBean.createObject0("cn.qf.Phone");
      //創建一個Phone對象 :泛型方法,不需要類型強轉
      Phone p2 = FactoryBean.createObject2("cn.qf.Phone");
      }
      }

      class Phone{
      private String phoneName;
      private Double phonePrice;
      ----
      }

        在這里我們使用工廠模式來創建對象,為了在我們獲取對象時,不用類型強轉,我們也使用了泛型。小伙伴通過代碼可以看到,不使用泛型的方法,在獲取對象時,需要類型強轉(可能會引起類型強轉異常)。

        在使用泛型方法獲取對象時,不需要類型強轉(可以避免引起類型強轉異常)。

        2.5 泛型方法、泛型接口、泛型類小結

        從上面的介紹小伙伴也看到了,泛型類的好處就是在泛型類上定義的泛型,在類的方法中也能使用(普通靜態方法除外)。而泛型方法的最大優點就是能獨立于類,不受類是否是泛型類的限制。因此當你考慮使用泛型的時候,優先考慮定義泛型方法。如果非要定義泛型類,

        個人建議通過使用泛型方法來將整個類泛型化,因為這樣就不用擔心靜態方法的事,如果有靜態方法那必然是泛型方法。這樣就能避免普通靜態方法無法獲取泛型類泛型的尷尬局面。

        你以為這就把泛型介紹完了嗎?并沒有,小伙伴們先休息片刻,稍后我們繼續喔。

        闖關練習

        需求:

        定義一個泛型類:

        包含與類的泛型一樣的變量,

        包含與類的泛型一樣的方法,參數也使用泛型

        同時定義一個類的泛型不相同的泛型方法

        答案:

      /**
      * 定義泛型類:
      * @param <T>: 泛型T
      */
      public class GenericDemo4<T> {
      //1.定義一個與T 一樣的變量
      private T t;
      //2.定義一個與T一樣的方法
      public T test1(T outer){
      System.out.println(outer);
      return outer;
      }
      //3.定義一個與T不一樣的方法
      public <E> E test2(E e){
      System.out.println("自定義泛型的方法:"+e);
      return e;
      }
      //測試:
      public static void main(String[] args) {
      //1.創建對象:指定T的泛型為 String
      GenericDemo4<String> gt = new GenericDemo4<String>();
      //2.調用 與T 一樣的泛型方法
      gt.test1("hello world");
      //3.調用 與T 不一樣的泛型方法
      gt.test2(10);
      }
      }

      好程序員公眾號

      • · 剖析行業發展趨勢
      • · 匯聚企業項目源碼

      好程序員開班動態

      More+
      • HTML5大前端 <高端班>

        開班時間:2021-04-12(深圳)

        開班盛況

        開班時間:2021-05-17(北京)

        開班盛況
      • 大數據+人工智能 <高端班>

        開班時間:2021-03-22(杭州)

        開班盛況

        開班時間:2021-04-26(北京)

        開班盛況
      • JavaEE分布式開發 <高端班>

        開班時間:2021-05-10(北京)

        開班盛況

        開班時間:2021-02-22(北京)

        開班盛況
      • Python人工智能+數據分析 <高端班>

        開班時間:2021-07-12(北京)

        預約報名

        開班時間:2020-09-21(上海)

        開班盛況
      • 云計算開發 <高端班>

        開班時間:2021-07-12(北京)

        預約報名

        開班時間:2019-07-22(北京)

        開班盛況
      IT培訓IT培訓
      在線咨詢
      IT培訓IT培訓
      試聽
      IT培訓IT培訓
      入學教程
      IT培訓IT培訓
      立即報名
      IT培訓

      Copyright 2011-2023 北京千鋒互聯科技有限公司 .All Right 京ICP備12003911號-5 京公網安備 11010802035720號

      91精品新拍在线观看,91精品一区二区,91精品一区二区三区久久久久,91精品在线播放,91精品中综合久久久久婷婷