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

java泛型基本知識(shí)和通用方法

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

一、泛型簡(jiǎn)介

1.引入泛型的目的

了解引入泛型的動(dòng)機(jī),就先從語(yǔ)法糖開(kāi)始了解。

語(yǔ)法糖

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

泛型的目的: Java 泛型就是把一種語(yǔ)法糖,通過(guò)泛型使得在編譯階段完成一些類(lèi)型轉(zhuǎn)換的工作,避免在運(yùn)行時(shí)強(qiáng)制類(lèi)型轉(zhuǎn)換而出現(xiàn)ClassCastException,即類(lèi)型轉(zhuǎn)換異常。

2.泛型初探

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

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

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

當(dāng)然這是完全允許的,因?yàn)長(zhǎng)ist里面的內(nèi)容是Object類(lèi)型的,自然任何對(duì)象類(lèi)型都可以放入、都可以取出,但是這么寫(xiě)會(huì)有兩個(gè)問(wèn)題:

1、當(dāng)一個(gè)對(duì)象放入集合時(shí),集合不會(huì)記住此對(duì)象的類(lèi)型,當(dāng)再次從集合中取出此對(duì)象時(shí),該對(duì)象的編譯類(lèi)型變成了Object。

2、運(yùn)行時(shí)需要人為地強(qiáng)制轉(zhuǎn)換類(lèi)型到具體目標(biāo),實(shí)際的程序絕不會(huì)這么簡(jiǎn)單,一個(gè)不小心就會(huì)出現(xiàn)java.lang.ClassCastException。

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

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

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

3.泛型的好處

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

②消除了代碼中許多的強(qiáng)制類(lèi)型轉(zhuǎn)換,增強(qiáng)了代碼的可讀性。

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

二、泛型的使用

1.泛型類(lèi)和泛型接口

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

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

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

下面具體講解泛型類(lèi)的使用。泛型接口的使用與泛型類(lèi)幾乎相同,可以比對(duì)自行學(xué)習(xí)。

泛型類(lèi)

定義一個(gè)容器類(lèi),存放鍵值對(duì)key-value,鍵值對(duì)的類(lèi)型不確定,可以使用泛型來(lái)定義,分別指定為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類(lèi)時(shí),只需要指定K,V的具體類(lèi)型即可,從而創(chuàng)建出邏輯上不同的Container實(shí)例,用來(lái)存放不同的數(shù)據(jù)類(lèi)型。

 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 增加了泛型的“菱形”語(yǔ)法:Java允許在構(gòu)造器后不需要帶完成的泛型信息,只要給出一對(duì)尖括號(hào)(<>)即可,Java可以推斷尖括號(hào)里應(yīng)該是什么泛型信息。

如下所示:

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

泛型類(lèi)派生子類(lèi)

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

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

正確的方式:

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

也可以不指定具體的類(lèi)型,如下:

public class A extends Container{}

此時(shí)系統(tǒng)會(huì)把K,V形參當(dāng)成Object類(lèi)型處理。

2.泛型的方法

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

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

但在另外一些情況下,在類(lèi)、接口中沒(méi)有使用泛型時(shí),定義方法時(shí)想定義類(lèi)型形參,就會(huì)使用泛型方法。如下方式:

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

所謂泛型方法,就是在聲明方法時(shí)定義一個(gè)或多個(gè)類(lèi)型形參。泛型方法的用法格式如下:

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

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

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

當(dāng)調(diào)用fun()方法時(shí),根據(jù)傳入的實(shí)際對(duì)象,編譯器就會(huì)判斷出類(lèi)型形參T所代表的實(shí)際類(lèi)型。

3.泛型構(gòu)造器

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

和使用普通泛型方法一樣沒(méi)區(qū)別,一種是顯式指定泛型參數(shù),另一種是隱式推斷,如果是顯式指定則以顯式指定的類(lèi)型參數(shù)為準(zhǔn),如果傳入的參數(shù)的類(lèi)型和指定的類(lèi)型實(shí)參不符,將會(huì)編譯報(bào)錯(cuò)。

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");
    }

這里唯一需要特殊注明的就是,如果構(gòu)造器是泛型構(gòu)造器,同時(shí)該類(lèi)也是一個(gè)泛型類(lèi)的情況下應(yīng)該如何使用泛型構(gòu)造器:

因?yàn)榉盒蜆?gòu)造器可以顯式指定自己的類(lèi)型參數(shù)(需要用到菱形,放在構(gòu)造器之前),而泛型類(lèi)自己的類(lèi)型實(shí)參也需要指定(菱形放在構(gòu)造器之后),這就同時(shí)出現(xiàn)了兩個(gè)菱形了,這就會(huì)有一些小問(wèn)題,具體用法再這里總結(jié)一下。

以下面這個(gè)例子為代表

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

這種用法:Person<String> a = new <Integer>Person<>(15); 這種語(yǔ)法不允許,會(huì)直接編譯報(bào)錯(cuò)!

三、類(lèi)型通配符

顧名思義就是匹配任意類(lèi)型的類(lèi)型實(shí)參。

類(lèi)型通配符是一個(gè)問(wèn)號(hào)(?),將一個(gè)問(wèn)號(hào)作為類(lèi)型實(shí)參傳給List集合,寫(xiě)作:List<?>(意思是元素類(lèi)型未知的List)。這個(gè)問(wèn)號(hào)(?)被成為通配符,它的元素類(lèi)型可以匹配任何類(lèi)型

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

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

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

但是并不能把元素加入到其中。因?yàn)槌绦驘o(wú)法確定c集合中元素的類(lèi)型,所以不能向其添加對(duì)象。下面就該引入帶限通配符,來(lái)確定集合元素中的類(lèi)型。

帶限通配符

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

主要分為兩類(lèi)即:上限通配符和下限通配符。

1.上限通配符

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

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

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

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

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

2.下限通配符

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

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

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

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

四、類(lèi)型擦除

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

程序輸出:

true。

這是因?yàn)椴还転榉盒偷念?lèi)型形參傳入哪一種類(lèi)型實(shí)參,對(duì)于Java來(lái)說(shuō),它們依然被當(dāng)成同一類(lèi)處理,在內(nèi)存中也只占用一塊內(nèi)存空間。從Java泛型這一概念提出的目的來(lái)看,其只是作用于代碼編譯階段,在編譯過(guò)程中,對(duì)于正確檢驗(yàn)泛型結(jié)果后,會(huì)將泛型的相關(guān)信息擦出,也就是說(shuō),成功編譯過(guò)后的class文件中是不包含任何泛型信息的。泛型信息不會(huì)進(jìn)入到運(yùn)行時(shí)階段。

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

總結(jié)

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

相關(guān)文章

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

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

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

    springmvc+mybatis 做分頁(yè)sql 語(yǔ)句實(shí)例代碼

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

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

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

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

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

    Java精品項(xiàng)目瑞吉外賣(mài)之后端登錄功能篇

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

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

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

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

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

    關(guān)于泛型擦除問(wèn)題的解決--Mybatis查詢類(lèi)型轉(zhuǎn)換

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

    Netty中的DelimiterBasedFrameDecoder使用方法詳解

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

    23種設(shè)計(jì)模式(10)java組合模式

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

最新評(píng)論