最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入理解java泛型Generic

 更新時(shí)間:2021年05月11日 14:54:43   作者:chengyu0726  
這篇文章主要介紹了深入理解java泛型Generic,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、背景

泛型技術(shù)誕生之前(JDK5以前),創(chuàng)建集合的類型都是Object 類型的元素,存儲(chǔ)內(nèi)容沒(méi)有限制,編譯時(shí)正常,運(yùn)行時(shí)容易出現(xiàn)ClassCastException 異常。

public class Test {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		list.add("java");
		list.add(100);
		list.add(true);
		for(int i = 0;i <list.size();i++) {
			Object o = list.get(i);
			String str = (String)o;
			System.out.println(str);
		}
	}
}

輸出:

java
Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.chengyu.junit.Test.main(Test.java:18)

二、泛型概念

JDK5 中引入泛型,從而可以在編譯時(shí)檢測(cè)是否存在非法的類型數(shù)據(jù)結(jié)構(gòu)
其本質(zhì)就是參數(shù)化類型,可以用于類、接口和方法中,分別被稱為泛型類、泛型接口、泛型方法。

public static void main(String[] args) {
		ArrayList<String> strList = new ArrayList<String>();
		strList.add("java");
		strList.add("C#");

		for(int i = 0;i < strList.size();i++) {
			String str = strList.get(i);
			System.out.println(str);
		}
	}

三、泛型類

3.1 定義與調(diào)用

定義類時(shí)設(shè)置泛型,該泛型可用于類中的屬性或方法中,調(diào)用該泛型類時(shí),指定具體類型;

// 調(diào)用泛型類
public class GenericTest {
	public static void main(String[] args) {
		Generic<String> strGen = new Generic<>("a");
		String key = strGen.getKey();
		System.out.println(key);
	}
}
// 定義泛型類
// @param <T> 使用類時(shí)指定
class Generic<T>{
	private T key;
	public Generic(T key) {
		this.key = key;
	}
	public T getKey() {
		return key;
	}
	public void setKey(T key) {
		this.key = key;
	}
	@Override
	public String toString() {
		return "GenericTest [key=" + key + "]";
	}
}

3.2 注意

1)調(diào)用泛型類時(shí)未定義類型,則會(huì)按照Object 類型處理;
2)調(diào)用時(shí)分別指定不同類型,但本質(zhì)都是Object 類型;
3)泛型不支持基本數(shù)據(jù)類型;
4)泛型類的成員方法不可以用static 修飾(泛型方法可以)。

3.3 使用

需求:抽獎(jiǎng)活動(dòng),但抽獎(jiǎng)內(nèi)容沒(méi)有確定,可能都是現(xiàn)金,也可能都是物品

public class ProductGetterTest {
	public static void main(String[] args) {
		// 抽物品
		ProductGetter<String> strProductGetter = new ProductGetter<>();
		String[] str = {"手機(jī)","電視","洗衣機(jī)"};
		for(int i = 0; i < str.length; i ++ ) {
			strProductGetter.addProduct(str[i]);
		}
		String strProduct = strProductGetter.getProduct();
		System.out.println("恭喜您抽中了" + strProduct);

		System.out.println("=============================================");
		// 抽現(xiàn)金
		ProductGetter<Integer> intProductGetter = new ProductGetter<>();
		Integer[] integer = {1000,2000,3000};
		for(int i = 0; i < integer.length; i ++ ) {
			intProductGetter.addProduct(integer[i]);
		}
		int intProduct = intProductGetter.getProduct();
		System.out.println("恭喜您抽中了" + intProduct);
	}
}
// 抽獎(jiǎng)器
class ProductGetter<T>{
	Random random = new Random();
	// 獎(jiǎng)品池
	ArrayList<T> list = new ArrayList<>();
	// 添加獎(jiǎng)品
	public void addProduct(T t) {
		list.add(t);
	}
	// 抽獎(jiǎng)(獲取獎(jiǎng)品)
	public T getProduct() {
		 return list.get(random.nextInt(list.size()));
	}
}

3.4 泛型類的繼承

3.4.1 子類也是泛型類

子類也是泛型類,則泛型要保持一致。

class ChildFirst<T> extends Parent{ ... }

1)指定子類泛型,不指定父類泛型,父類默認(rèn)為Object 類型

class Parent<E>{
	private E value;
	public E getValue() {
		return value;
	}
	public void setValue(E value) {
		this.value = value;
	}
}
class ChildFirst<T> extends Parent{
	@Override
	public Object getValue() {
		return super.getValue();
	}
}

2)若父類保留原有泛型,與子類泛型不一致,則會(huì)編譯出錯(cuò)

class ChildFirst<T> extends Parent<E>{
	@Override
	public E getValue() {
		return super.getValue(); 
	}

3)父類泛型與子類保持一致
具體泛型指定是由子類傳遞到父類當(dāng)中,所以繼承時(shí)父類要與子類泛型保持一致(當(dāng)然都寫成E也可以)。

class Parent<E>{
	private E value;
	public E getValue() {
		return value;
	}
	public void setValue(E value) {
		this.value = value;
	}
}
class ChildFirst<T> extends Parent<T>{
	@Override
	public T getValue() {
		return super.getValue();
	}
}

4)調(diào)用

public class GenericTest {
	public static void main(String[] args) {
		ChildFirst<String> childFirst = new ChildFirst<>();
		childFirst.setValue("chengyu");
		System.out.println(childFirst.getValue());
	}
}

5)補(bǔ)充:
子類可以進(jìn)行泛型擴(kuò)展,但子類必須有一個(gè)泛型與父類一致

public class GenericTest {
	public static void main(String[] args) {
		ChildFirst<String,Integer> childFirst = new ChildFirst<>();
		childFirst.setValue("chengyu");
		System.out.println(childFirst.getValue());
	}
}
class Parent<E>{
	private E value;
	public E getValue() {
		return value;
	}
	public void setValue(E value) {
		this.value = value;
	}
}
class ChildFirst<T,E> extends Parent<T>{
	@Override
	public T getValue() {
		return super.getValue();
	}
}

3.4.2 子類不是泛型類

子類不是泛型類,父類要明確泛型的數(shù)據(jù)類型

class ChildSecond extends Parent<String>{ ... }

1)子類不是泛型類,不指定父類泛型,父類默認(rèn)為Object 類型

class Parent<E>{
	private E value;
	public E getValue() {
		return value;
	}
	public void setValue(E value) {
		this.value = value;
	}
}
class ChildSecond extends Parent{
	@Override
	public Object getValue() {
		return super.getValue();
	}
}

2)父類要明確泛型的數(shù)據(jù)類型

class ChildSecond extends Parent<String>{
	@Override
	public String getValue() {
		return super.getValue();
	}
}

3)調(diào)用

public class GenericTest {
	public static void main(String[] args) {
		ChildSecond childSecond = new ChildSecond();
		childSecond.setValue("chengyu2");
		System.out.println(childSecond.getValue());
	}
}

四、泛型接口

4.1 定義

public interface Generator<T>{ ... }

4.2 使用(與繼承特點(diǎn)相同)

4.2.1 實(shí)現(xiàn)類不是泛型類

實(shí)現(xiàn)類不是泛型類,接口要明確數(shù)據(jù)類型

class Apple implements Generator<String>{
	@Override
	public String getKey() {
		return "Generator interface";
	}
}

4.2.2 實(shí)現(xiàn)類也是泛型類

實(shí)現(xiàn)類也是泛型類,實(shí)現(xiàn)類和接口的泛型類型要一致

class Apple<T> implements Generator<T>{
	private T key;
	@Override
	public T getKey() {
		return key;
	}
}

五、泛型方法

5.1 定義

5.1.1 泛型方法

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

// 泛型方法
public <E,T> E getProduct(ArrayList<E> list) {
	return list.get(random.nextInt(list.size()));
}

5.1.2 靜態(tài)泛型方法

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

// 泛型方法
public <E,T> E getProduct(ArrayList<E> list) {
	return list.get(random.nextInt(list.size()));
}

5.1.3 可變參數(shù)的泛型方法

public <E> void print(E... e) {
	for(int i = 0; i < e.length;i++){
		System.out.println(e[i]);
	}
}
// 調(diào)用
print(1,2,3,4);

5.2 注意

1)包含泛型列表的方法才是泛型方法,泛型類中使用了泛型的方法并不是泛型方法;
2)泛型列表中聲明了泛型類型,才可以在方法中使用泛型類型;
3)泛型方法中的泛型類型獨(dú)立于泛型類的泛型,與類泛型類型無(wú)關(guān);
4)泛型方法可以用static 修飾(泛型類的成員方法不可以)。

5.3 使用

5.3.1 定義泛型方法

// 抽獎(jiǎng)器
// @param <t>
class ProductGetter<T>{
	Random random = new Random();
	// 獎(jiǎng)品池
	ArrayList<T> list = new ArrayList<>();
	// 添加獎(jiǎng)品
	public void addProduct(T t) {
		list.add(t);
	}
	// 抽獎(jiǎng)(獲取獎(jiǎng)品)
	public T getProduct() {
		 return list.get(random.nextInt(list.size()));
	}
	// 泛型方法
	public <E> E getProduct(ArrayList<E> list) {
		return list.get(random.nextInt(list.size()));
	}
}

5.3.2 調(diào)用泛型方法

public class ProductGetterTest {
	public static void main(String[] args) {
		ProductGetter<Integer> intProductGetter = new ProductGetter<>();

		ArrayList<String> strList = new ArrayList<>();
		strList.add("手機(jī)");
		strList.add("電視");
		strList.add("洗衣機(jī)");

		String product = intProductGetter.getProduct(strList);
		System.out.println("恭喜您抽中了" + product);
	}
}

六、類型通配符

6.1 類型通配符介紹

類型通配符一般用【?】代替具體的類型 實(shí)參

6.2 為什么要用類型通配符

泛型類被調(diào)用時(shí),需要指定泛型類型,當(dāng)泛型類的方法被調(diào)用時(shí),不能靈活對(duì)應(yīng)多種泛型類型的需求,如下面代碼部分所示:

public class BoxTest {
	public static void main(String[] args) {
		// 3.調(diào)用showBox
		Box<Number> box1 = new Box<>();
		box1.setFirst(100);
		showBox(box1);
		// 4.再次調(diào)用showBox
		// 出現(xiàn)問(wèn)題:類型發(fā)生變化后會(huì)報(bào)錯(cuò)
		Box<Integer> box2 = new Box<>();
		box2.setFirst(200);
		showBox(box2);
	}
	// 2. 調(diào)用泛型類,此時(shí)需要指定泛型類型
	public static void showBox(Box<Number> box) {
		Number first = box.getFirst();
		System.out.println(first);
	}
}
// 1.定義泛型類
class Box<E>{
	private E first;
	public E getFirst() {
		return first;
	}
	public void setFirst(E first) {
		this.first = first;
	}
}

解決上述問(wèn)題,類型通配符【?】登場(chǎng)

public class BoxTest {
	public static void main(String[] args) {
		// 3.調(diào)用showBox
		Box<Number> box1 = new Box<>();
		box1.setFirst(100);
		showBox(box1);
		// 4.再次調(diào)用showBox
		// 問(wèn)題得以解決
		Box<Integer> box2 = new Box<>();
		box2.setFirst(200);
		showBox(box2);
	}
	// 2. 調(diào)用泛型類,此時(shí)需要指定泛型類型
	// 【?】類型通配符等成
	public static void showBox(Box<?> box) {
		Object first = box.getFirst();
		System.out.println(first);
	}
}
// 1.定義泛型類
class Box<E>{
	private E first;
	public E getFirst() {
		return first;
	}
	public void setFirst(E first) {
		this.first = first;
	}
}

6.3 泛型通配符上限 extends

【6.2】代碼例中,雖然使用了通配符,但 box.getFirst()返回類型仍然需要定義成Object 類型,并不理想。

public static void showBox(Box<?> box) {
	Object first = box.getFirst();
	System.out.println(first);
}

通配符上限登場(chǎng):
調(diào)用showBox 方法時(shí),傳遞的泛型類型可以是Number 及其子類(Integer)

public static void showBox(Box<? extends Number> box) {
	Number first = box.getFirst();
	System.out.println(first);
}

注意:

public static void showBox(Box<? extends Number> box) {
	Number first = box.getFirst();
	// 此處編譯報(bào)錯(cuò):類型不一致
	// 雖然定義上限,showBox 被調(diào)用時(shí)沒(méi)問(wèn)題,但在方法內(nèi)同時(shí)定義多種類型,編譯器無(wú)法識(shí)別
	Integer second = box.getFirst();
	System.out.println(first);
}

6.4 泛型通配符下限 super

public static void showBox(Box<? super Integer> box) {
	Number first = box.getFirst();
	System.out.println(first);
}

注意:
遍歷時(shí)要用Object 類型進(jìn)行遍歷;

七、類型擦除

泛型信息只存在于代碼編譯階段,進(jìn)入JVM之前,與泛型相關(guān)的信息會(huì)被擦除,這個(gè)行為稱為類型擦除。

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

相關(guān)文章

  • MyBatis XPathParser解析器使用范例詳解

    MyBatis XPathParser解析器使用范例詳解

    這篇文章主要介紹了關(guān)于MyBatis中解析器XPathParser的實(shí)際使用實(shí)踐,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2022-07-07
  • 使用SpringBoot的CommandLineRunner遇到的坑及解決

    使用SpringBoot的CommandLineRunner遇到的坑及解決

    這篇文章主要介紹了使用SpringBoot的CommandLineRunner遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Spring循環(huán)依賴的處理方法

    Spring循環(huán)依賴的處理方法

    循環(huán)依賴是指兩個(gè)或多個(gè)組件之間相互依賴,形成一個(gè)閉環(huán),從而導(dǎo)致這些組件無(wú)法正確地被初始化或加載,這篇文章主要介紹了Spring循環(huán)依賴的處理,需要的朋友可以參考下
    2023-08-08
  • Spring?boot集成easy?excel實(shí)現(xiàn)導(dǎo)入導(dǎo)出功能

    Spring?boot集成easy?excel實(shí)現(xiàn)導(dǎo)入導(dǎo)出功能

    這篇文章主要介紹了Spring?boot集成easy?excel實(shí)現(xiàn)導(dǎo)入導(dǎo)出操作,使用easyexcel,首先要引入easyexcel的maven依賴,具體的版本根據(jù)你的需求去設(shè)置,本文結(jié)合實(shí)例代碼講解的非常詳細(xì),需要的朋友可以參考下
    2024-05-05
  • springboot 使用QQ郵箱發(fā)送郵件的操作方法

    springboot 使用QQ郵箱發(fā)送郵件的操作方法

    這篇文章主要介紹了springboot使用QQ郵箱發(fā)送郵件功能,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • java文件重命名(文件批量重命名)實(shí)例程序代碼分享

    java文件重命名(文件批量重命名)實(shí)例程序代碼分享

    這篇文章主要介紹了java文件重命名的程序代碼,大家參考使用吧
    2013-12-12
  • MyBatis?insert實(shí)體如何返回主鍵

    MyBatis?insert實(shí)體如何返回主鍵

    這篇文章主要介紹了MyBatis?insert實(shí)體如何返回主鍵,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Nacos集群模式下服務(wù)無(wú)法注冊(cè)問(wèn)題

    Nacos集群模式下服務(wù)無(wú)法注冊(cè)問(wèn)題

    這篇文章主要介紹了Nacos集群模式下服務(wù)無(wú)法注冊(cè)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java通過(guò)Freemarker模板實(shí)現(xiàn)生成Word文件

    Java通過(guò)Freemarker模板實(shí)現(xiàn)生成Word文件

    FreeMarker是一款模板引擎: 即一種基于模板和要改變的數(shù)據(jù), 并用來(lái)生成輸出文本的通用工具。本文將根據(jù)Freemarker模板實(shí)現(xiàn)生成Word文件,需要的可以參考一下
    2022-09-09
  • 手把手搭建Java共享網(wǎng)盤的方法步驟

    手把手搭建Java共享網(wǎng)盤的方法步驟

    這篇文章主要介紹了手把手搭建Java共享網(wǎng)盤,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評(píng)論

阳山县| 深圳市| 甘谷县| 岳普湖县| 武川县| 福建省| 南和县| 泰顺县| 工布江达县| 邛崃市| 新营市| 洛川县| 金川县| 茌平县| 望江县| 沿河| 宜川县| 台前县| 乌拉特中旗| 松阳县| 关岭| 南丹县| 祁阳县| 宝应县| 万山特区| 全南县| 沙雅县| 义马市| 万荣县| 安国市| 乐平市| 永昌县| 泰和县| 叙永县| 阿鲁科尔沁旗| 临沭县| 洛扎县| 房山区| 建始县| 新泰市| 德阳市|