Java?中的泛型超全詳解
一、泛型概述
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ù)化, 也就是說在泛型使用過程中,數(shù)據(jù)類型被設(shè)置為一個(gè)參數(shù),在使用時(shí)再?gòu)耐獠總魅胍粋€(gè)數(shù)據(jù)類型;而一旦傳入了具體的數(shù)據(jù)類型后,傳入變量(實(shí)參)的數(shù)據(jù)類型如果不匹配,編譯器就會(huì)直接報(bào)錯(cuò)。這種參數(shù)化類型可以用在類、接口和方法中,分別被稱為泛型類、泛型接口、泛型方法。
//沒有泛型的時(shí)候,集合如何存儲(chǔ)數(shù)據(jù)
//結(jié)論:
//如果我們沒有給集合指定類型,默認(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);
}
}
}上面代碼沒有任何問題,在遍歷 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í)沒有報(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 異常的問題(這樣體現(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 常見的泛型標(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)定義過了
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ù)化,它通過擦除的方式來(lái)實(shí)現(xiàn),即編譯器會(huì)在編譯期間擦除代碼中的所有泛型語(yǔ)法并相應(yīng)的做出一些類型轉(zhuǎn)換動(dòng)作。
換而言之,泛型信息只存在于代碼編譯階段,在代碼編譯結(jié)束后,與泛型相關(guān)的信息會(huì)被擦除掉,專業(yè)術(shù)語(yǔ)叫做類型擦除。也就是說,成功編譯過后的 class 文件中不包含任何泛型信息,泛型信息不會(huì)進(jìn)入到運(yùn)行時(shí)階段。
其實(shí)Java中的泛型本質(zhì)是偽泛型
當(dāng)把集合定義為string類型的時(shí)候,當(dāng)數(shù)據(jù)添加在集合當(dāng)中的時(shí)候,僅僅在門口檢查了一下數(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 集合,不過一個(gè)是 ArrayList< String>,只能存儲(chǔ)字符串。一個(gè)是 ArrayList< Integer>,只能存儲(chǔ)整型對(duì)象。我們通過 arrayString 對(duì)象和 arrayInteger 對(duì)象的 getClass() 方法獲取它們的類信息并比較,發(fā)現(xiàn)結(jié)果為true。
明明我們?cè)?<> 中傳入了兩種不同的數(shù)據(jù)類型,那為什么它們的類信息還是相同呢? 這是因?yàn)?,在編譯期間,所有的泛型信息都會(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)生了疑問:
不是說泛型信息在編譯的時(shí)候就會(huì)被擦除掉嗎?那既然泛型信息被擦除了,如何保證我們?cè)诩现兄惶砑又付ǖ臄?shù)據(jù)類型的對(duì)象呢?
換而言之,我們雖然定義了 ArrayList< Integer > 泛型集合,但其泛型信息最終被擦除后就變成了 ArrayList< Object > 集合,那為什么不允許向其中插入 String 對(duì)象呢?
Java 是如何解決這個(gè)問題的?
其實(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è)置的門票類型;
當(dāng)驗(yàn)票系統(tǒng)設(shè)置好為< Integer >后,只有持有 Integer 門票的人才可以通過驗(yàn)票系統(tǒng),進(jìn)入演唱會(huì)場(chǎng)館(集合)中;若是未持有 Integer 門票的人想進(jìn)場(chǎng),則驗(yàn)票系統(tǒng)會(huì)發(fā)出警告(編譯器報(bào)錯(cuò))。
在通過驗(yàn)票系統(tǒng)時(shí),門票會(huì)被收掉(類型擦除),但場(chǎng)館后臺(tái)(JVM)會(huì)記錄下觀眾信息(泛型信息)。
進(jìn)場(chǎng)后的觀眾變成了沒有門票的普通人(原始數(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)票,門票會(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)換。也就是說,編譯器把 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í),泛型里面寫的什么類型,那么就傳遞什么類型的數(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í),泛型里面寫的什么類型,那么就傳遞什么類型的數(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í),泛型里面寫的是什么類型,那么只能傳遞什么類型的數(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í),泛型里面寫的是什么類型,那么只能傳遞什么類型的數(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)物
| |
貓 狗
| | | |
波斯貓 貍花貓 泰迪 哈士奇
屬性:名字,年齡
行為:吃東西
波斯貓方法體打?。阂恢唤凶鯴XX的,X歲的波斯貓,正在吃小餅干
貍花貓方法體打?。阂恢唤凶鯴XX的,X歲的貍花貓,正在吃魚
泰迪方法體打?。阂恢唤凶鯴XX的,X歲的泰迪,正在吃骨頭,邊吃邊蹭
哈士奇方法體打?。阂恢唤凶鯴XX的,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歲的貍花貓,正在吃魚
泰迪方法體打?。阂恢唤凶鯴XX的,X歲的泰迪,正在吃骨頭,邊吃邊蹭
哈士奇方法體打?。阂恢唤凶鯴XX的,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() + "歲的貍花貓,正在吃魚");
}
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)文章
Java并發(fā)容器相關(guān)知識(shí)總結(jié)
今天給大家?guī)?lái)的文章是Java并發(fā)容器的相關(guān)知識(shí),文中有非常詳細(xì)的介紹,對(duì)正在學(xué)習(xí)Java并發(fā)容器的小伙伴們很有幫助,需要的朋友可以參考下2021-06-06
淺談@RequestParam(required = true)的誤區(qū)
這篇文章主要介紹了@RequestParam(required = true)的誤區(qū),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
使用Spring掃描Mybatis的mapper接口的三種配置
這篇文章主要介紹了使用Spring掃描Mybatis的mapper接口的三種配置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
2020macOS Big Sur配置Java開發(fā)環(huán)境之jdk安裝過程
這篇文章主要介紹了2020macOS Big Sur配置Java開發(fā)環(huán)境之jdk安裝,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
springboot項(xiàng)目使用Disruptor做內(nèi)部消息隊(duì)列的實(shí)現(xiàn)
本文主要介紹了springboot項(xiàng)目使用Disruptor做內(nèi)部消息隊(duì)列的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
java中獲取類加載路徑和項(xiàng)目根路徑的5種方式分析
本篇文章介紹了,java中獲取類加載路徑和項(xiàng)目根路徑的5種方式分析。需要的朋友參考下2013-05-05
ShardingSphere結(jié)合MySQL實(shí)現(xiàn)分庫(kù)分表的項(xiàng)目實(shí)踐
在實(shí)際開發(fā)中,如果表的數(shù)據(jù)過大我們需要把一張表拆分成多張表,本文主要介紹了使用ShardingSphere實(shí)現(xiàn)MySQL分庫(kù)分表,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
Java詳細(xì)分析連接數(shù)據(jù)庫(kù)的流程
Java數(shù)據(jù)庫(kù)連接,JDBC是Java語(yǔ)言中用來(lái)規(guī)范客戶端程序如何來(lái)訪問數(shù)據(jù)庫(kù)的應(yīng)用程序接口,提供了諸如查詢和更新數(shù)據(jù)庫(kù)中數(shù)據(jù)的方法。JDBC也是Sun Microsystems的商標(biāo)。我們通常說的JDBC是面向關(guān)系型數(shù)據(jù)庫(kù)的2022-05-05

