亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java?中的泛型超全詳解

 更新時(shí)間:2025年03月04日 09:41:42   作者:林的快手  
這篇文章主要介紹了泛型的概念、使用場(chǎng)景、泛型類、泛型方法、泛型接口、類型擦除以及泛型通配符,泛型是一種強(qiáng)大的工具,可以幫助我們編寫(xiě)更安全和更通用的代碼,感興趣的朋友一起看看吧

一、泛型概述

1. 什么是泛型?為什么要使用泛型?

泛型,即“參數(shù)化類型”。一提到參數(shù),最熟悉的就是定義方法時(shí)有形參列表,普通方法的形參列表中,每個(gè)形參的數(shù)據(jù)類型是確定的,而變量是一個(gè)參數(shù)。在調(diào)用普通方法時(shí)需要傳入對(duì)應(yīng)形參數(shù)據(jù)類型的變量(實(shí)參),若傳入的實(shí)參與形參定義的數(shù)據(jù)類型不匹配,則會(huì)報(bào)錯(cuò)

參數(shù)化類型是什么?以方法的定義為例,在方法定義時(shí),將方法簽名中的形參的數(shù)據(jù)類型也設(shè)置為參數(shù)(也可稱之為類型參數(shù)),在調(diào)用該方法時(shí)再?gòu)耐獠總魅胍粋€(gè)具體的數(shù)據(jù)類型和變量。

泛型的本質(zhì)是為了將類型參數(shù)化, 也就是說(shuō)在泛型使用過(guò)程中,數(shù)據(jù)類型被設(shè)置為一個(gè)參數(shù),在使用時(shí)再?gòu)耐獠總魅胍粋€(gè)數(shù)據(jù)類型;而一旦傳入了具體的數(shù)據(jù)類型后,傳入變量(實(shí)參)的數(shù)據(jù)類型如果不匹配,編譯器就會(huì)直接報(bào)錯(cuò)。這種參數(shù)化類型可以用在類、接口和方法中,分別被稱為泛型類、泛型接口、泛型方法。

//沒(méi)有泛型的時(shí)候,集合如何存儲(chǔ)數(shù)據(jù)
//結(jié)論:
//如果我們沒(méi)有給集合指定類型,默認(rèn)認(rèn)為所有的數(shù)據(jù)類型都是Object類型
//此時(shí)可以往集合添加任意的數(shù)據(jù)類型。
//帶來(lái)一個(gè)壞處:我們?cè)讷@取數(shù)據(jù)的時(shí)候,無(wú)法使用他的特有行為。

//此時(shí)推出了泛型,可以在添加數(shù)據(jù)的時(shí)候就把類型進(jìn)行統(tǒng)一。
//而且我們?cè)讷@取數(shù)據(jù)的時(shí)候,也省的強(qiáng)轉(zhuǎn)了,非常的方便。

2. 泛型使用場(chǎng)景

在 ArrayList 集合中,可以放入所有類型的對(duì)象,假設(shè)現(xiàn)在需要一個(gè)只存儲(chǔ)了 String 類型對(duì)象的 ArrayList 集合。

public class demo1 {
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        for(String s:list){
            System.out.println(s);
        }
    }
}
上面代碼沒(méi)有任何問(wèn)題,在遍歷 ArrayList 集合時(shí),只需將 Object 對(duì)象進(jìn)行向下轉(zhuǎn)型成 String 類型即可得到 String 類型對(duì)象。

但如果在添加 String 對(duì)象時(shí),不小心添加了一個(gè) Integer 對(duì)象,會(huì)發(fā)生什么?看下面代碼:

 public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add(666);
        for (int i = 0; i < list.size(); i++) {
            System.out.println((String)list.get(i));
        }
    }

上述代碼在編譯時(shí)沒(méi)有報(bào)錯(cuò),但在運(yùn)行時(shí)卻拋出了一個(gè) ClassCastException 異常,其原因是 Integer 對(duì)象不能強(qiáng)轉(zhuǎn)為 String 類型。

那如何可以避免上述異常的出現(xiàn)?即我們希望當(dāng)我們向集合中添加了不符合類型要求的對(duì)象時(shí),編譯器能直接給我們報(bào)錯(cuò),而不是在程序運(yùn)行后才產(chǎn)生異常。這個(gè)時(shí)候便可以使用泛型了。

使用泛型代碼如下:

 public static void main(String[] args) {
        ArrayList<String> list = new ArrayList();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        //list.add(666);// 在編譯階段,編譯器會(huì)報(bào)錯(cuò)
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
< String > 是一個(gè)泛型,其限制了 ArrayList 集合中存放對(duì)象的數(shù)據(jù)類型只能是 String,當(dāng)添加一個(gè)非 String 對(duì)象時(shí),編譯器會(huì)直接報(bào)錯(cuò)。這樣,我們便解決了上面產(chǎn)生的 ClassCastException 異常的問(wèn)題(這樣體現(xiàn)了泛型的類型安全檢測(cè)機(jī)制)。

3.總結(jié)

泛型的出現(xiàn)就是為了統(tǒng)一集合當(dāng)中數(shù)據(jù)類型的

二、泛型類 泛型類的定義

  • 尖括號(hào) <> 中的 泛型標(biāo)識(shí)被稱作是類型參數(shù),用于指代任何數(shù)據(jù)類型。
  • 泛型標(biāo)識(shí)是任意設(shè)置的(如果你想可以設(shè)置為 Hello都行),Java 常見(jiàn)的泛型標(biāo)識(shí)以及其代表含義如下:

  T :代表一般的任何類。
  E :代表 Element 元素的意思,或者 Exception 異常的意思。
  K :代表 Key 的意思。
  V :代表 Value 的意思,通常與 K 一起配合使用。
  S :代表 Subtype 的意思,文章后面部分會(huì)講解示意。

 自己實(shí)現(xiàn)集合

代碼如下:

package fangxing;
import java.util.Arrays;
public class MyArrayList<E> {
    Object[] obj = new Object[10];
    int size = 0;
    /*
    E: 表示不確定的類型,該類型在類名后面已經(jīng)定義過(guò)了
    e: 形參的名字,變量名
     */
    public boolean add(E e) {
        obj[size++] = e;
        return true;
        //當(dāng)添加成功以后,集合還是會(huì)把這些數(shù)據(jù)當(dāng)做Object類型處理
    }
    public E get(int index) {
        return (E) obj[index];
        //獲取的時(shí)候集合在把他強(qiáng)轉(zhuǎn)<E>類型
    }
    @Override
    public String toString() {
           return Arrays.toString(obj);
    }
}
package fangxing;
import javax.xml.stream.events.StartDocument;
public class demo3 {
    public static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        System.out.println(list);
    }
}

三、泛型方法

格式

package fangxing;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ListUtil {
    private ListUtil() {
    }
    /*
    參數(shù)一:集合
    參數(shù)二: 最后要添加的元素
     */
    public static <E> void addAll(ArrayList<E> list, E e1, E e2) {
        list.add(e1);
        list.add(e2);
    }
}
 
package fangxing;
import java.util.ArrayList;
public class demo4 {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        ListUtil.addAll(list,"zhangsan","lisi");
        System.out.println(list);//[zhangsan, lisi]
    }
}

添加很多元素

public static <E> void addAll(ArrayList<E> list, E ...e1) {
        for (E e : e1) {
          list.add(e);
        }

四、泛型接口

方法1:實(shí)現(xiàn)類給出具體類型

舉例:

public class MyArrayList2  implements List<String> 
public static void main(String[] args) {
        MyArrayList2 list2=new MyArrayList2();
    }

方法2: 實(shí)現(xiàn)類延續(xù)泛型,創(chuàng)建對(duì)象再確定

public class MyArrayList3 <E>  implements List<E>
  MyArrayList3<String> list = new MyArrayList3<>();

五、類型擦除

1. 什么是類型擦除


泛型的本質(zhì)是將數(shù)據(jù)類型參數(shù)化,它通過(guò)擦除的方式來(lái)實(shí)現(xiàn),即編譯器會(huì)在編譯期間擦除代碼中的所有泛型語(yǔ)法并相應(yīng)的做出一些類型轉(zhuǎn)換動(dòng)作。

換而言之,泛型信息只存在于代碼編譯階段,在代碼編譯結(jié)束后,與泛型相關(guān)的信息會(huì)被擦除掉,專業(yè)術(shù)語(yǔ)叫做類型擦除。也就是說(shuō),成功編譯過(guò)后的 class 文件中不包含任何泛型信息,泛型信息不會(huì)進(jìn)入到運(yùn)行時(shí)階段。

其實(shí)Java中的泛型本質(zhì)是偽泛型

當(dāng)把集合定義為string類型的時(shí)候,當(dāng)數(shù)據(jù)添加在集合當(dāng)中的時(shí)候,僅僅在門(mén)口檢查了一下數(shù)據(jù)是否符合String類型,  如果是String類型,就添加成功,當(dāng)添加成功以后,集合還是會(huì)把這些數(shù)據(jù)當(dāng)做Object類型處理,當(dāng)往外獲取的時(shí)候,集合在把他強(qiáng)轉(zhuǎn)String類型

 當(dāng)代碼編譯到class文件的時(shí)候,泛型就消失,叫泛型的擦除

看一個(gè)例子,假如我們給 ArrayList 集合傳入兩種不同的數(shù)據(jù)類型,并比較它們的類信息。

public class GenericType {
    public static void main(String[] args) {  
        ArrayList<String> arrayString = new ArrayList<String>();   
        ArrayList<Integer> arrayInteger = new ArrayList<Integer>();   
        System.out.println(arrayString.getClass() == arrayInteger.getClass());// true
    }  
}

在這個(gè)例子中,我們定義了兩個(gè) ArrayList 集合,不過(guò)一個(gè)是 ArrayList< String>,只能存儲(chǔ)字符串。一個(gè)是 ArrayList< Integer>,只能存儲(chǔ)整型對(duì)象。我們通過(guò) arrayString 對(duì)象和 arrayInteger 對(duì)象的 getClass() 方法獲取它們的類信息并比較,發(fā)現(xiàn)結(jié)果為true。

明明我們?cè)?<> 中傳入了兩種不同的數(shù)據(jù)類型,那為什么它們的類信息還是相同呢? 這是因?yàn)椋诰幾g期間,所有的泛型信息都會(huì)被擦除, ArrayList< Integer > 和 ArrayList< String >類型,在編譯后都會(huì)變成ArrayList< Objec t>類型。

那么是不是所有的類型參數(shù)被擦除后都以 Object 類進(jìn)行替換呢?

答案是否定的,大部分情況下,類型參數(shù) T 被擦除后都會(huì)以 Object 類進(jìn)行替換;而有一種情況則不是,那就是使用到了 extends 和 super 語(yǔ)法的有界類型參數(shù)(即泛型通配符,后面我們會(huì)詳細(xì)解釋 

2. 類型擦除的原理

假如我們定義了一個(gè) ArrayList< Integer > 泛型集合,若向該集合中插入 String 類型的對(duì)象,不需要運(yùn)行程序,編譯器就會(huì)直接報(bào)錯(cuò)。這里可能有小伙伴就產(chǎn)生了疑問(wèn):

不是說(shuō)泛型信息在編譯的時(shí)候就會(huì)被擦除掉嗎?那既然泛型信息被擦除了,如何保證我們?cè)诩现兄惶砑又付ǖ臄?shù)據(jù)類型的對(duì)象呢?

換而言之,我們雖然定義了 ArrayList< Integer > 泛型集合,但其泛型信息最終被擦除后就變成了 ArrayList< Object > 集合,那為什么不允許向其中插入 String 對(duì)象呢?

Java 是如何解決這個(gè)問(wèn)題的?

其實(shí)在創(chuàng)建一個(gè)泛型類的對(duì)象時(shí), Java 編譯器是先檢查代碼中傳入 < T > 的數(shù)據(jù)類型,并記錄下來(lái),然后再對(duì)代碼進(jìn)行編譯,編譯的同時(shí)進(jìn)行類型擦除;如果需要對(duì)被擦除了泛型信息的對(duì)象進(jìn)行操作,編譯器會(huì)自動(dòng)將對(duì)象進(jìn)行類型轉(zhuǎn)換。

可以把泛型的類型安全檢查機(jī)制和類型擦除想象成演唱會(huì)的驗(yàn)票機(jī)制:以 ArrayList< Integer> 泛型集合為例。

當(dāng)我們?cè)趧?chuàng)建一個(gè) ArrayList< Integer > 泛型集合的時(shí)候,ArrayList 可以看作是演唱會(huì)場(chǎng)館,而< T >就是場(chǎng)館的驗(yàn)票系統(tǒng),Integer 是驗(yàn)票系統(tǒng)設(shè)置的門(mén)票類型;
當(dāng)驗(yàn)票系統(tǒng)設(shè)置好為< Integer >后,只有持有 Integer 門(mén)票的人才可以通過(guò)驗(yàn)票系統(tǒng),進(jìn)入演唱會(huì)場(chǎng)館(集合)中;若是未持有 Integer 門(mén)票的人想進(jìn)場(chǎng),則驗(yàn)票系統(tǒng)會(huì)發(fā)出警告(編譯器報(bào)錯(cuò))。
在通過(guò)驗(yàn)票系統(tǒng)時(shí),門(mén)票會(huì)被收掉(類型擦除),但場(chǎng)館后臺(tái)(JVM)會(huì)記錄下觀眾信息(泛型信息)。
進(jìn)場(chǎng)后的觀眾變成了沒(méi)有門(mén)票的普通人(原始數(shù)據(jù)類型)。但是,在需要查看觀眾的信息時(shí)(操作對(duì)象),場(chǎng)館后臺(tái)可以找到記錄的觀眾信息(編譯器會(huì)自動(dòng)將對(duì)象進(jìn)行類型轉(zhuǎn)換)。
 

舉例如下:

public class GenericType {
    public static void main(String[] args) {  
        ArrayList<Integer> arrayInteger = new ArrayList<Integer>();// 設(shè)置驗(yàn)票系統(tǒng)   
        arrayInteger.add(111);// 觀眾進(jìn)場(chǎng),驗(yàn)票系統(tǒng)驗(yàn)票,門(mén)票會(huì)被收走(類型擦除)
        Integer n = arrayInteger.get(0);// 獲取觀眾信息,編譯器會(huì)進(jìn)行強(qiáng)制類型轉(zhuǎn)換
        System.out.println(n);
    }  
}

擦除 ArrayList< Integer > 的泛型信息后,get() 方法的返回值將返回 Object 類型,但編譯器會(huì)自動(dòng)插入 Integer 的強(qiáng)制類型轉(zhuǎn)換。也就是說(shuō),編譯器把 get() 方法調(diào)用翻譯為兩條字節(jié)碼指令:

對(duì)原始方法 get() 的調(diào)用,返回的是 Object 類型;
將返回的 Object 類型強(qiáng)制轉(zhuǎn)換為 Integer 類型;

代碼如下:

Integer n = arrayInteger.get(0);// 這條代碼底層如下:
	//(1)get() 方法的返回值返回的是 Object 類型
	Object object = arrayInteger.get(0);
	//(2)編譯器自動(dòng)插入 Integer 的強(qiáng)制類型轉(zhuǎn)換
	Integer n = (Integer) object;

3. 類型擦除小結(jié)

1.泛型信息(包括泛型類、接口、方法)只在代碼編譯階段存在,在代碼成功編譯后,其內(nèi)的所有泛型信息都會(huì)被擦除,并且類型參數(shù) T 會(huì)被統(tǒng)一替換為其原始類型(默認(rèn)是 Object 類,若有 extends 或者 super 則另外分析);

2.在泛型信息被擦除后,若還需要使用到對(duì)象相關(guān)的泛型信息,編譯器底層會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)換(從原始類型轉(zhuǎn)換為未擦除前的數(shù)據(jù)類型)。

六、泛型通配符

1. 泛型的繼承

泛型不具備繼承性,但是數(shù)據(jù)具備繼承性

  此時(shí),泛型里面寫(xiě)的什么類型,那么就傳遞什么類型的數(shù)據(jù)

泛型不具備繼承性舉例

package fangxing;
import java.util.ArrayList;
public class demo5 {
    public static void main(String[] args) {
        /*
        泛型不具備繼承性,但是數(shù)據(jù)具備繼承性
         */
        ArrayList<Ye> list1=new ArrayList<>();
        ArrayList<Fu> list2=new ArrayList<>();
        ArrayList<Zi> list3=new ArrayList<>();
        //調(diào)用method方法
        method(list1);
        //method(list2);//編譯錯(cuò)誤
//method(list3);//編譯錯(cuò)誤
    }
    /*
    此時(shí),泛型里面寫(xiě)的什么類型,那么就傳遞什么類型的數(shù)據(jù)
     */
    public static  void method(ArrayList<Ye> list){
    }
}
class Ye{
}
class Fu extends Ye{
}
class Zi extends Fu{
}

數(shù)據(jù)具備繼承性 

   //數(shù)據(jù)具備繼承性
        list1.add(new Ye());//添加爺爺?shù)膶?duì)象等
        list1.add(new Fu());
        list1.add(new Zi());

定義一個(gè)方法,形參是一個(gè)集合,但是集合中的數(shù)據(jù)類型不確定。

應(yīng)用場(chǎng)景:
*      1.如果我們?cè)诙x類、方法、接口的時(shí)候,如果類型不確定,就可以定義泛型類、泛型方法、泛型接口。
*      2.如果類型不確定,但是能知道以后只能傳遞某個(gè)繼承體系中的,就可以泛型的通配符
* 泛型的通配符:
*      關(guān)鍵點(diǎn):可以限定類型的范圍。

/*
 * 此時(shí),泛型里面寫(xiě)的是什么類型,那么只能傳遞什么類型的數(shù)據(jù)。
 * 弊端:
 *      利用泛型方法有一個(gè)小弊端,此時(shí)他可以接受任意的數(shù)據(jù)類型
 *      Ye  Fu   Zi    Student
 *
 * 希望:本方法雖然不確定類型,但是以后我希望只能傳遞Ye Fu Zi
 *
 * 此時(shí)我們就可以使用泛型的通配符:
 *      ?也表示不確定的類型
 *      他可以進(jìn)行類型的限定
 *      ? extends E: 表示可以傳遞E或者E所有的子類類型
 *      ? super E:表示可以傳遞E或者E所有的父類類型
 *

舉例

package fangxing;
import java.util.ArrayList;
/*
 *   需求:
 *       定義一個(gè)方法,形參是一個(gè)集合,但是集合中的數(shù)據(jù)類型不確定。
 *
 * */
/*
 * 此時(shí),泛型里面寫(xiě)的是什么類型,那么只能傳遞什么類型的數(shù)據(jù)。
 * 弊端:
 *      利用泛型方法有一個(gè)小弊端,此時(shí)他可以接受任意的數(shù)據(jù)類型
 *      Ye  Fu   Zi    Student
 *
 * 希望:本方法雖然不確定類型,但是以后我希望只能傳遞Ye Fu Zi
 *
 * 此時(shí)我們就可以使用泛型的通配符:
 *      ?也表示不確定的類型
 *      他可以進(jìn)行類型的限定
 *      ? extends E: 表示可以傳遞E或者E所有的子類類型
 *      ? super E:表示可以傳遞E或者E所有的父類類型
 *
 * 應(yīng)用場(chǎng)景:
 *      1.如果我們?cè)诙x類、方法、接口的時(shí)候,如果類型不確定,就可以定義泛型類、泛型方法、泛型接口。
 *      2.如果類型不確定,但是能知道以后只能傳遞某個(gè)繼承體系中的,就可以泛型的通配符
 * 泛型的通配符:
 *      關(guān)鍵點(diǎn):可以限定類型的范圍。
 *
 * */
public class demo6 {
    public static void main(String[] args) {
        //創(chuàng)建集合的對(duì)象
        ArrayList<Ye> list1 = new ArrayList<>();
        ArrayList<Fu> list2 = new ArrayList<>();
        ArrayList<Zi> list3 = new ArrayList<>();
        ArrayList<Student2> list4 = new ArrayList<>();
        method(list1);
        method(list2);
        //method(list3);
        //method(list4);
    }
    public static void method(ArrayList<? super Fu> list) {
    }
}
class Ye {
}
class Fu extends Ye {
}
class Zi extends Fu {
}
class Student2{}

2.練習(xí)

/*
      需求:
          定義一個(gè)繼承結(jié)構(gòu):
                              動(dòng)物
                   |                           |
                   貓                          狗
                |      |                    |      |
             波斯貓   貍花貓                泰迪   哈士奇
           屬性:名字,年齡
           行為:吃東西
                 波斯貓方法體打印:一只叫做XXX的,X歲的波斯貓,正在吃小餅干
                 貍花貓方法體打印:一只叫做XXX的,X歲的貍花貓,正在吃魚(yú)
                 泰迪方法體打?。阂恢唤凶鯴XX的,X歲的泰迪,正在吃骨頭,邊吃邊蹭
                 哈士奇方法體打印:一只叫做XXX的,X歲的哈士奇,正在吃骨頭,邊吃邊拆家

      測(cè)試類中定義一個(gè)方法用于飼養(yǎng)動(dòng)物
          public static void keepPet(ArrayList<???> list){
              //遍歷集合,調(diào)用動(dòng)物的eat方法
          }
      要求1:該方法能養(yǎng)所有品種的貓,但是不能養(yǎng)狗
      要求2:該方法能養(yǎng)所有品種的狗,但是不能養(yǎng)貓
      要求3:該方法能養(yǎng)所有的動(dòng)物,但是不能傳遞其他類型
   */

測(cè)試類

package lx;
import java.util.ArrayList;
public class demo1 {
    /*
          需求:
              定義一個(gè)繼承結(jié)構(gòu):
                                  動(dòng)物
                       |                           |
                       貓                          狗
                    |      |                    |      |
                 波斯貓   貍花貓                泰迪   哈士奇
               屬性:名字,年齡
               行為:吃東西
                     波斯貓方法體打?。阂恢唤凶鯴XX的,X歲的波斯貓,正在吃小餅干
                     貍花貓方法體打?。阂恢唤凶鯴XX的,X歲的貍花貓,正在吃魚(yú)
                     泰迪方法體打?。阂恢唤凶鯴XX的,X歲的泰迪,正在吃骨頭,邊吃邊蹭
                     哈士奇方法體打印:一只叫做XXX的,X歲的哈士奇,正在吃骨頭,邊吃邊拆家
          測(cè)試類中定義一個(gè)方法用于飼養(yǎng)動(dòng)物
              public static void keepPet(ArrayList<???> list){
                  //遍歷集合,調(diào)用動(dòng)物的eat方法
              }
          要求1:該方法能養(yǎng)所有品種的貓,但是不能養(yǎng)狗
          要求2:該方法能養(yǎng)所有品種的狗,但是不能養(yǎng)貓
          要求3:該方法能養(yǎng)所有的動(dòng)物,但是不能傳遞其他類型
       */
    public static void main(String[] args) {
        HuskyDog h = new HuskyDog("哈士奇", 1);
        LihuaCat l = new LihuaCat("貍花貓", 2);
        PersianCat p = new PersianCat("波斯貓", 3);
        TeddyDog t = new TeddyDog("泰迪", 4);
        ArrayList<LihuaCat> list1 = new ArrayList<>();
        ArrayList<PersianCat> list2 = new ArrayList<>();
        // 向列表中添加一些貓的實(shí)例
        list1.add(l);
        list2.add(p);
        //調(diào)用方法
        keepPet1(list1);
        keepPet1(list2);
        System.out.println("-------------------------------------------");
        ArrayList<HuskyDog> list3 = new ArrayList<>();
        ArrayList<TeddyDog> list4 = new ArrayList<>();
        // 向列表中添加一些狗的實(shí)例
        list3.add(h);
        list4.add(t);
        //調(diào)用方法
        keepPet2(list3);
        keepPet2(list4);
        System.out.println("-------------------------------------------");
        list1.add(l);
        list2.add(p);
        list3.add(h);
        list4.add(t);
        keepPet3(list1);
        keepPet3(list2);
        keepPet3(list3);
        keepPet3(list4);
    }
    /*
    此時(shí)我們就可以使用泛型的通配符:
      ?也表示不確定的類型
      他可以進(jìn)行類型的限定
      ? extends E: 表示可以傳遞E或者E所有的子類類型
     ? super E:表示可以傳遞E或者E所有的父類類型
     */
    //  要求1:該方法能養(yǎng)所有品種的貓,但是不能養(yǎng)狗
    public static void keepPet1(ArrayList<? extends Cat> list) {
        //遍歷集合,調(diào)用動(dòng)物的eat方法
        for (Cat cat : list) {
            cat.eat();
        }
    }
    //  要求2:該方法能養(yǎng)所有品種的狗,但是不能養(yǎng)貓
    public static void keepPet2(ArrayList<? extends Dog> list) {
        //遍歷集合,調(diào)用動(dòng)物的eat方法
        for (Dog dog : list) {
            dog.eat();
        }
    }
    //  要求3:該方法能養(yǎng)所有的動(dòng)物,但是不能傳遞其他類型
    public static void keepPet3(ArrayList<? extends Animal> list) {
        //遍歷集合,調(diào)用動(dòng)物的eat方法
        for (Animal animal : list) {
            animal.eat();
        }
    }
}

Animal類

package lx;
public abstract class Animal {
    private String name;
    private int age;
    public Animal() {
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 獲取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 設(shè)置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 獲取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 設(shè)置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Animal{name = " + name + ", age = " + age + "}";
    }
    public abstract  void eat();
}

cat類型

package lx;
public abstract class Cat extends Animal{
    public Cat() {
    }
    public Cat(String name, int age) {
        super(name, age);
    }
}

Dog類

package lx;
public abstract class Dog extends Animal{
    public Dog() {
    }
    public Dog(String name, int age) {
        super(name, age);
    }
}

哈士奇類

package lx;
public class HuskyDog extends Dog{
    @Override
    public void eat() {
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"歲的哈士奇,正在吃骨頭,邊吃邊拆家");
    }
    public HuskyDog() {
    }
    public HuskyDog(String name, int age) {
        super(name, age);
    }
}

貍花貓類

package lx;
public class LihuaCat extends Cat {
    @Override
    public void eat() {
        System.out.println("一只叫做" + getName() + "的," + getAge() + "歲的貍花貓,正在吃魚(yú)");
    }
    public LihuaCat() {
    }
    public LihuaCat(String name, int age) {
        super(name, age);
    }
}

波斯貓類

package lx;
public class PersianCat extends Cat{
    @Override
    public void eat() {
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"歲的波斯貓,正在吃小餅干");
    }
    public PersianCat() {
    }
    public PersianCat(String name, int age) {
        super(name, age);
    }
}

泰迪貓類

package lx;
public class TeddyDog extends Dog{
    @Override
    public void eat() {
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"歲泰迪,正在吃骨頭,邊吃邊蹭");
    }
    public TeddyDog() {
    }
    public TeddyDog(String name, int age) {
        super(name, age);
    }
}

總結(jié)

到此這篇關(guān)于Java 中的泛型超全詳解的文章就介紹到這了,更多相關(guān)java泛型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論