欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java泛型基本知識和通用方法

 更新時間:2021年06月25日 17:31:17   作者:蔚藍的海洋  
這篇文章主要介紹了java泛型基礎知識及通用方法,從以下幾個方面介紹一下java的泛型: 基礎, 泛型關鍵字, 泛型方法, 泛型類和接口,感興趣的可以了解一下

一、泛型簡介

1.引入泛型的目的

了解引入泛型的動機,就先從語法糖開始了解。

語法糖

語法糖(Syntactic Sugar),也稱糖衣語法,是由英國計算機學家Peter.J.Landin發(fā)明的一個術語,指在計算機語言中添加的某種語法,這種語法對語言的功能并沒有影響,但是更方便程序員使用。Java中最常用的語法糖主要有泛型、變長參數(shù)、條件編譯、自動拆裝箱、內(nèi)部類等。虛擬機并不支持這些語法,它們在編譯階段就被還原回了簡單的基礎語法結構,這個過程成為解語法糖。

泛型的目的: Java 泛型就是把一種語法糖,通過泛型使得在編譯階段完成一些類型轉換的工作,避免在運行時強制類型轉換而出現(xiàn)ClassCastException,即類型轉換異常。

2.泛型初探

JDK 1.5 時才增加了泛型,并在很大程度上都是方便集合的使用,使其能夠記住其元素的數(shù)據(jù)類型。

在泛型(Generic type或Generics)出現(xiàn)之前,是這么寫代碼的:

public static void main(String[] args)
{
    List list = new ArrayList();
    list.add("123");
    list.add("456");
    System.out.println((String)list.get(0));
}

當然這是完全允許的,因為List里面的內(nèi)容是Object類型的,自然任何對象類型都可以放入、都可以取出,但是這么寫會有兩個問題:

1、當一個對象放入集合時,集合不會記住此對象的類型,當再次從集合中取出此對象時,該對象的編譯類型變成了Object。

2、運行時需要人為地強制轉換類型到具體目標,實際的程序絕不會這么簡單,一個不小心就會出現(xiàn)java.lang.ClassCastException。

所以,泛型出現(xiàn)之后,上面的代碼就改成了大家都熟知的寫法:

public static void main(String[] args)
{
    List<String> list = new ArrayList<String>();
    list.add("123");
    list.add("456");
    System.out.println(list.get(0));
}

這就是泛型。泛型是對Java語言類型系統(tǒng)的一種擴展,有點類似于C++的模板,可以把類型參數(shù)看作是使用參數(shù)化類型時指定的類型的一個占位符。引入泛型,是對Java語言一個較大的功能增強,帶來了很多的好處。

3.泛型的好處

①類型安全。類型錯誤現(xiàn)在在編譯期間就被捕獲到了,而不是在運行時當作java.lang.ClassCastException展示出來,將類型檢查從運行時挪到編譯時有助于開發(fā)者更容易找到錯誤,并提高程序的可靠性。

②消除了代碼中許多的強制類型轉換,增強了代碼的可讀性。

③為較大的優(yōu)化帶來了可能。

二、泛型的使用

1.泛型類和泛型接口

下面是JDK 1.5 以后,List接口,以及ArrayList類的代碼片段。

//定義接口時指定了一個類型形參,該形參名為E
public interface List<E> extends Collection<E> {
   //在該接口里,E可以作為類型使用
   public E get(int index) {}
   public void add(E e) {} 
}
//定義類時指定了一個類型形參,該形參名為E
public class ArrayList<E> extends AbstractList<E> implements List<E>{
   //在該類里,E可以作為類型使用
   public void set(E e) {
   .......................
   }
}

這就是泛型的實質:允許在定義接口、類時聲明類型形參,類型形參在整個接口、類體內(nèi)可當成類型使用,幾乎所有可使用普通類型的地方都可以使用這種類型形參。

下面具體講解泛型類的使用。泛型接口的使用與泛型類幾乎相同,可以比對自行學習。

泛型類

定義一個容器類,存放鍵值對key-value,鍵值對的類型不確定,可以使用泛型來定義,分別指定為K和V

public class Container<K, V> {
    private K key;
    private V value;
    public Container(K k, V v) {
        key = k;
        value = v;
    }
    public K getkey() {
        return key;
    }
    public V getValue() {
        return value;
    }
    public void setKey() {
        this.key = key;
    }
    public void setValue() {
        this.value = value;
    }
}

在使用Container類時,只需要指定K,V的具體類型即可,從而創(chuàng)建出邏輯上不同的Container實例,用來存放不同的數(shù)據(jù)類型。

 public static void main(String[] args){
                  Container<String,String> c1=new Container<String ,String>("name","hello");
                  Container<String,Integer> c2=new Container<String,Integer>("age",22);
                  Container<Double,Double> c3=new Container<Double,Double>(1.1,1.3);
                  System.out.println(c1.getKey() + " : " + c1.getValue());      
                  System.out.println(c2.getKey() + " : " + c2.getValue());                                                               
                  System.out.println(c3.getKey() + " : " + c3.getValue());
        }

在JDK 1.7 增加了泛型的“菱形”語法:Java允許在構造器后不需要帶完成的泛型信息,只要給出一對尖括號(<>)即可,Java可以推斷尖括號里應該是什么泛型信息。

如下所示:

Container<String,String> c1=new Container<>("name","hello");
Container<String,Integer> c2=new Container<>("age",22);

泛型類派生子類

當創(chuàng)建了帶泛型聲明的接口、父類之后,可以為該接口創(chuàng)建實現(xiàn)類,或者從該父類派生子類,需要注意:使用這些接口、父類派生子類時不能再包含類型形參,需要傳入具體的類型。錯誤的方式:

public class A extends Container<K, V>{}

正確的方式:

public class A extends Container<Integer, String>{}

也可以不指定具體的類型,如下:

public class A extends Container{}

此時系統(tǒng)會把K,V形參當成Object類型處理。

2.泛型的方法

前面在介紹泛型類和泛型接口中提到,可以在泛型類、泛型接口的方法中,把泛型中聲明的類型形參當成普通類型使用。 如下面的方式:

public class Container<K, V> {
........................
    public K getkey() {
        return key;
    }
    public void setKey() {
        this.key = key;
    }
....................
}

但在另外一些情況下,在類、接口中沒有使用泛型時,定義方法時想定義類型形參,就會使用泛型方法。如下方式:

public class Main{
      public static <T> void out(T t){
                System.out.println(t);
      }
      public static void main(String[] args){
              out("hansheng");
              out(123);
      }
}

所謂泛型方法,就是在聲明方法時定義一個或多個類型形參。泛型方法的用法格式如下:

修飾符<T, S> 返回值類型 方法名(形參列表)
{
方法體
 }

注意:方法聲明中定義的形參只能在該方法里使用,而接口、類聲明中定義的類型形參則可以在整個接口、類中使用。

class Demo{  
     public <T> T fun(T t){   // 可以接收任意類型的數(shù)據(jù)  
     	 return t ;     // 直接把參數(shù)返回  
     }  
}
public class GenericsDemo26{  
     public static void main(String args[]){  
          Demo d = new Demo() ; // 實例化Demo對象  
          String str = d.fun("湯姆") ; // 傳遞字符串  
          int i = d.fun(30) ;  // 傳遞數(shù)字,自動裝箱  
          System.out.println(str) ; // 輸出內(nèi)容  
          System.out.println(i) ;  // 輸出內(nèi)容  
     }  
}; 

當調用fun()方法時,根據(jù)傳入的實際對象,編譯器就會判斷出類型形參T所代表的實際類型。

3.泛型構造器

正如泛型方法允許在方法簽名中聲明類型形參一樣,Java也允許在構造器簽名中聲明類型形參,這樣就產(chǎn)生了所謂的泛型構造器。

和使用普通泛型方法一樣沒區(qū)別,一種是顯式指定泛型參數(shù),另一種是隱式推斷,如果是顯式指定則以顯式指定的類型參數(shù)為準,如果傳入的參數(shù)的類型和指定的類型實參不符,將會編譯報錯。

public class Person {
    public <T> Person(T t) {
        System.out.println(t);
    }
}
public static void main(String[] args){
        //隱式
        new Person(22);
        //顯示
        new<String>Person("hello");
    }

這里唯一需要特殊注明的就是,如果構造器是泛型構造器,同時該類也是一個泛型類的情況下應該如何使用泛型構造器:

因為泛型構造器可以顯式指定自己的類型參數(shù)(需要用到菱形,放在構造器之前),而泛型類自己的類型實參也需要指定(菱形放在構造器之后),這就同時出現(xiàn)了兩個菱形了,這就會有一些小問題,具體用法再這里總結一下。

以下面這個例子為代表

public class Person<E> {
    public <T> Person(T t) {
        System.out.println(t);
    }
}

這種用法:Person<String> a = new <Integer>Person<>(15); 這種語法不允許,會直接編譯報錯!

三、類型通配符

顧名思義就是匹配任意類型的類型實參。

類型通配符是一個問號(?),將一個問號作為類型實參傳給List集合,寫作:List<?>(意思是元素類型未知的List)。這個問號(?)被成為通配符,它的元素類型可以匹配任何類型

public void test(List<?> c){
    for(int i =0;i<c.size();i++){
        System.out.println(c.get(i));
    }
}

現(xiàn)在可以傳入任何類型的List來調用test()方法,程序依然可以訪問集合c中的元素,其類型是Object。

List<?> c = new ArrayList<String>();
        //編譯器報錯
        c.add(new Object());

但是并不能把元素加入到其中。因為程序無法確定c集合中元素的類型,所以不能向其添加對象。下面就該引入帶限通配符,來確定集合元素中的類型。

帶限通配符

簡單來講,使用通配符的目的是來限制泛型的類型參數(shù)的類型,使其滿足某種條件,固定為某些類。

主要分為兩類即:上限通配符和下限通配符。

1.上限通配符

如果想限制使用泛型類別時,只能用某個特定類型或者是其子類型才能實例化該類型時,可以在定義類型時,使用extends關鍵字指定這個類型必須是繼承某個類,或者實現(xiàn)某個接口,也可以是這個類或接口本身。。

它表示集合中的所有元素都是Shape類型或者其子類
List<? extends Shape>

這就是所謂的上限通配符,使用關鍵字extends來實現(xiàn),實例化時,指定類型實參只能是extends后類型的子類或其本身。例如:

//Circle是其子類
List<? extends Shape> list = new ArrayList<Circle>();

這樣就確定集合中元素的類型,雖然不確定具體的類型,但最起碼知道其父類。然后進行其他操作。

2.下限通配符

如果想限制使用泛型類別時,只能用某個特定類型或者是其父類型才能實例化該類型時,可以在定義類型時,使用super關鍵字指定這個類型必須是是某個類的父類,或者是某個接口的父接口,也可以是這個類或接口本身。

它表示集合中的所有元素都是Circle類型或者其父類
List<? super Circle>

這就是所謂的下限通配符,使用關鍵字super來實現(xiàn),實例化時,指定類型實參只能是extends后類型的子類或其本身。例如:

它表示集合中的所有元素都是Circle類型或者其父類
List<? super Circle>

四、類型擦除

Class c1 = new ArrayList<Integer>().getClass();
Class c2 = new ArrayList<String>().getClass();
System.out.println(c1==c2);

程序輸出:

true。

這是因為不管為泛型的類型形參傳入哪一種類型實參,對于Java來說,它們依然被當成同一類處理,在內(nèi)存中也只占用一塊內(nèi)存空間。從Java泛型這一概念提出的目的來看,其只是作用于代碼編譯階段,在編譯過程中,對于正確檢驗泛型結果后,會將泛型的相關信息擦出,也就是說,成功編譯過后的class文件中是不包含任何泛型信息的。泛型信息不會進入到運行時階段。

在靜態(tài)方法、靜態(tài)初始化塊或者靜態(tài)變量的聲明和初始化中不允許使用類型形參。由于系統(tǒng)中并不會真正生成泛型類,所以instanceof運算符后不能使用泛型類。

總結

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!

相關文章

  • 如何在Spring中自定義scope的方法示例

    如何在Spring中自定義scope的方法示例

    這篇文章主要介紹了如何在Spring中自定義scope的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • springmvc+mybatis 做分頁sql 語句實例代碼

    springmvc+mybatis 做分頁sql 語句實例代碼

    本文通過一段實例代碼給大家介紹了springmvc+mybatis 做分頁sql 語句的方法,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-07-07
  • JAVA實現(xiàn)讀取txt文件內(nèi)容的方法

    JAVA實現(xiàn)讀取txt文件內(nèi)容的方法

    本篇文章主要介紹了JAVA實現(xiàn)讀取txt文件內(nèi)容的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • SpringBoot參數(shù)校驗的最佳實戰(zhàn)教程

    SpringBoot參數(shù)校驗的最佳實戰(zhàn)教程

    開發(fā)過程中,后臺的參數(shù)校驗是必不可少的,下面這篇文章主要給大家介紹了關于SpringBoot參數(shù)校驗的最佳實戰(zhàn),文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-08-08
  • Java精品項目瑞吉外賣之后端登錄功能篇

    Java精品項目瑞吉外賣之后端登錄功能篇

    這篇文章主要為大家詳細介紹了java精品項目-瑞吉外賣訂餐系統(tǒng),此項目過大,分為多章獨立講解,本篇內(nèi)容為后端登錄功能的實現(xiàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 使用棧的迷宮算法java版代碼

    使用棧的迷宮算法java版代碼

    這篇文章主要為大家詳細介紹了使用棧的迷宮算法java版代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java實戰(zhàn)入門之雙色球彩票小游戲

    Java實戰(zhàn)入門之雙色球彩票小游戲

    這篇文章主要介紹了Java實戰(zhàn)入門之雙色球彩票,文中有非常詳細的代碼示例,對正在學習java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 關于泛型擦除問題的解決--Mybatis查詢類型轉換

    關于泛型擦除問題的解決--Mybatis查詢類型轉換

    這篇文章主要介紹了關于泛型擦除問題的解決--Mybatis查詢類型轉換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Netty中的DelimiterBasedFrameDecoder使用方法詳解

    Netty中的DelimiterBasedFrameDecoder使用方法詳解

    這篇文章主要介紹了Netty中的DelimiterBasedFrameDecoder使用方法詳解,DelimiterBasedFrameDecoder與LineBasedFrameDecoder類似,只不過更加通用,允許我們指定任意特殊字符作為分隔符,我們還可以同時指定多個分隔符,需要的朋友可以參考下
    2023-12-12
  • 23種設計模式(10)java組合模式

    23種設計模式(10)java組合模式

    這篇文章主要為大家詳細介紹了23種設計模式之java組合模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11

最新評論