泛型的使用

泛型的使用泛型的作用簡(jiǎn)單的泛型類泛型方法有限制的通配符擦除和翻譯

泛型的使用

集合沒(méi)有泛型的時(shí)候咖杂,集合存放數(shù)據(jù)時(shí)都會(huì)丟失原來(lái)的類型庆寺,全部改為Object。這樣可以獲得良好的通用性诉字。但是取出的時(shí)候懦尝,就需要做類型轉(zhuǎn)換,如果類型寫錯(cuò)了壤圃,轉(zhuǎn)換就會(huì)出現(xiàn)異常陵霉。為了有更好的安全性和可讀性,Java在JDK1.5的時(shí)候加入了泛型伍绳。

泛型的應(yīng)用非常重要踊挠,在教學(xué)中,務(wù)必讓學(xué)生學(xué)會(huì)基本的使用:

  1. 在集合(List墨叛、Set止毕、Map)上使用泛型

  2. 在通用類或者接口上使用泛型

  3. 在方法上使用泛型

  4. 明白什么是泛型擦除

泛型的作用

使用泛型機(jī)制編寫的程序代碼要比那些雜亂地使用Object 變量 模蜡,然后再進(jìn)行強(qiáng)制類型轉(zhuǎn)換的代碼具有更好的安全性和可讀性 漠趁。泛型對(duì)于集合類尤其有用 ,例如 忍疾,ArrayList就是一個(gè)無(wú)處不在的集合類

沒(méi)有泛型的代碼:

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n18" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">List<String> list = new ArrayList<>();

list.add(123);
list.add("abc");
list.add(1>2);
list.add('E');
list.add(890.12);

for (int i = 0; i < list.size(); i++) {
System.out.println( list.get(i) );
}</pre>

輸入什么類型闯传,就輸出什么類型。但是我希望list里面存放的數(shù)據(jù)類型只有字符串怎么辦 卤妒?沒(méi)有代碼的情況下代碼是這樣的:

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n20" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">List list = new ArrayList();

list.add("123.A");
list.add("abc.def");

for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);
System.out.println( str.split("\.")[0] ) ;
}</pre>

但是list中如果有其他類型呢甥绿?

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n22" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">List list = new ArrayList();

list.add("123.A");
list.add(123.123); // 這行數(shù)據(jù)就是一個(gè)浮點(diǎn)型
list.add("abc.def");

for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);
System.out.println( str.split("\.")[0] ) ;
}</pre>

[圖片上傳失敗...(image-72ef90-1627791165361)]

發(fā)生了類型轉(zhuǎn)換錯(cuò)誤~~

為了解決這類問(wèn)題,使用泛型是不二之選则披。通過(guò)泛型可以限制集合中數(shù)據(jù)的類型共缕,只有符合的類型才能放到集合中

格式

在聲明的集合類型后面跟上一對(duì)尖括號(hào),實(shí)現(xiàn)的類型構(gòu)造器的小括號(hào)前面跟上一對(duì)尖括號(hào)士复。里面寫上需要存放的數(shù)據(jù)類型

[圖片上傳失敗...(image-217b41-1627791165361)]

可以看到图谷,在定義泛型后,添加 123.123 浮點(diǎn)數(shù)時(shí)編譯器就開(kāi)始報(bào)錯(cuò)了阱洪。在使用泛型后便贵,代碼也不需要做類型強(qiáng)轉(zhuǎn)了。

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n30" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">List<String> list = new ArrayList<String>();

list.add("123.A");
list.add("abc.def");

for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
System.out.println( str.split("\.")[0] ) ;
}</pre>

Map的演示

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n32" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">Map<String, String> data = new HashMap<>();

data.put("name", "張三");
data.put("age", "11歲");
data.put("sex", "男");

for (Map.Entry<String, String> entry: data.entrySet()) {
System.out.println( entry.getKey() +":"+ entry.getValue());
}</pre>

簡(jiǎn)單的泛型類

在定義類 Pair 時(shí)冗荸,在類名后跟上 <T>

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n36" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">public class Pair<T> {
private T first;
private T second;

public Pair() {
first = null;
second = null;
}

public Pair(T first , T second){
this.first = first;
this.second = second;
}

public void setFirst(T newValue) {
first = newValue;
}

public void setSecond(T newValue) {
second = newValue;
}

public T getFirst() {
return first;
}

public T getSecond() {
return second;
}

@Override
public String toString() {
return "Pair [first=" + first + ", second=" + second + "]";
}
}</pre>

使用

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n38" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">public static void main(String[] args) {

System.out.println(new Pair<Integer>(1, 2));
//輸出: Pair [first=1, second=2]

System.out.println(new Pair<String>("諸葛", "孔明"));
//輸出: Pair [first=諸葛, second=孔明]
}</pre>

使用泛型承璃,就如同將原來(lái)類定義的 T 替換為了指定的類型版本一樣,比如:

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n40" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">public class Pair {
private Integer first;
private Integer second;

public Pair() {
first = null;
second = null;
}

public Pair(Integer first , Integer second){
this.first = first;
this.second = second;
}
//....
}</pre>

類型參數(shù)就跟在方法或構(gòu)造函數(shù)中普通的參數(shù)一樣蚌本。就像一個(gè)方法有形式參數(shù)(formal value parameters)來(lái)描述它操作的參數(shù)的種類一樣盔粹,一個(gè)泛型聲明也有形式類型參數(shù)(formal type parameters)隘梨。當(dāng)一個(gè)方法被調(diào)用,實(shí)參(actual arguments)替換形參舷嗡,方法體被執(zhí)行出嘹。當(dāng)一個(gè)泛型聲明被調(diào)用,實(shí)際類型參數(shù)(actual type arguments)取代形式類型參數(shù)咬崔。

泛型方法

在使用前税稼,我們先明確一下泛型的各種通配符:

  1. T:type 數(shù)據(jù)類型

  2. E:element 元素

  3. K:key 鍵

  4. V:value 值

  5. ?:未知類型

示例:

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="java" cid="n57" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">class ArrayAlg {

public static <T> T getMiddle(T... a) {
    return a[a.length / 2];
}

}</pre>

測(cè)試

同一個(gè)類的方法,使用不同類型的數(shù)組垮斯,都可以正常得到數(shù)據(jù)

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="java" cid="n60" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">String[] array = {"123","345","456" , "567"};
String string = ArrayAlg.getMiddle(array);
System.out.println( string );

Integer[] array2 = {33,44,55,66,77,88};
System.out.println( ArrayAlg.getMiddle(array2) );</pre>

有限制的通配符

考慮一個(gè)簡(jiǎn)單的畫圖程序郎仆,它可以用來(lái)畫各種形狀,比如矩形和圓形兜蠕。 為了在程序中表示這些形狀扰肌,你可以定義下面的類繼承結(jié)構(gòu):

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="java" cid="n65" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">// 抽象類
public abstract class Shape {
public abstract void draw();
}

// 畫布
public class Canvas {
public void draw(Shape s) {
s.draw();
}
}

/// ---- 抽象類的子類-----------------------

public class Circle extends Shape {

private int x, y, radius;

public void draw() { 
    // ...
}

}

public class Rectangle extends Shape {
private int x, y, width, height;

public void draw() {
    // ... 
}

}</pre>

所有的圖形通常都有很多個(gè)形狀。假定它們用一個(gè) list 來(lái)表示熊杨,Canvas 里有一個(gè)方法來(lái)畫出所有的形狀會(huì)比較方便

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="java" cid="n67" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">import java.util.List;

public class Canvas {
public void draw(Shape s) {
s.draw();
}

public void drawAll(List<Shape> shapes) {
    for (Shape s : shapes) {
        s.draw();
    }
}

}</pre>

現(xiàn)在曙旭,類型規(guī)則導(dǎo)致 drawAll()只能使用 Shape的list 來(lái)調(diào)用。它不能晶府,比如說(shuō)對(duì) List<Circle>來(lái)調(diào)用桂躏。 這很不幸, 因?yàn)檫@個(gè)方法所作的只是從這個(gè) list 讀取 shape川陆,因此它應(yīng)該也能對(duì) List<Circle>調(diào)用剂习。我們真正要的是這個(gè)方法能夠接受一個(gè)任意種類的 shape

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="java" cid="n69" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">import java.util.List;

public class Canvas {
public void draw(Shape s) {
s.draw();
}

// 注意方法參數(shù)的變化
public void drawAll(List<? extends Shape> shapes) { 
    for (Shape s : shapes) {
        s.draw();
    }
}

}</pre>

我們把類型 List<Shape> 替換成了 List<? extends Shape>。現(xiàn)在drawAll()可以接受任何 Shape 的子類的 List较沪,所以我們可以對(duì) List<Circle>進(jìn)行調(diào)用

List<? extends Shape>是有限制通配符的一個(gè)例子鳞绕。這里?代表一個(gè)未知的類型尸曼,就像我們前面看到的通配符一樣们何。但是,在這里控轿,我們知道這個(gè)未知的類型實(shí)際上是Shape 的一個(gè)子類(它可以是 Shape本身或者 Shape 的子類而不必是 extends 自 Shape)冤竹。我們說(shuō) Shape是這個(gè)通配符的上限(upper bound)。 像平常一樣解幽,要得到使用通配符的靈活性有些代價(jià)贴见。這個(gè)代價(jià)是,現(xiàn)在向 shapes 中寫入是非法的躲株。比如下面的代碼是不允許的

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="java" cid="n72" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">public void addRectangle(List<? extends Shape> shapes) {
// 編譯時(shí)會(huì)報(bào)錯(cuò)
shapes.add( new Rectangle());
}</pre>

shapes.add 的第二個(gè)參數(shù)類型是? extends Shape ——一個(gè) Shape 未知的子類片部。因此我們不知道這個(gè)類型是什么,我們不知道它是不是 Rectangle 的父類;它可能是也可能不是一個(gè)父類档悠,所以這里傳遞一個(gè) Rectangle 不安全

擦除和翻譯

先看下面的代碼

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="java" cid="n77" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">public static String loophole(Integer x) {
List<String> ys = new LinkedList<String>();
List xs = ys;
xs.add(x);
return ys.iterator().next();
}

public static void main(String[] args) {
loophole(123);
}</pre>

[圖片上傳失敗...(image-436467-1627791165359)]

可以看到廊鸥,程序類型的轉(zhuǎn)換異常,但是編譯器卻沒(méi)有報(bào)錯(cuò)

這樣的原因是辖所,泛型是通過(guò) java 編譯器的稱為擦除(erasure)的前端處理來(lái)實(shí)現(xiàn)的惰说。你可以(基本上就是)把它認(rèn)為是一個(gè)從源碼到源碼的轉(zhuǎn)換,它把泛型版本的 loophole()轉(zhuǎn)換成非泛型版本缘回。 結(jié)果是吆视,java 虛擬機(jī)的類型安全和穩(wěn)定性決不能冒險(xiǎn),即使在又unchecked warning 的情況下酥宴。

擦除去掉了所有的泛型類型信息啦吧。所有在尖括號(hào)之間的類型信息都被扔掉了,因此拙寡,比如說(shuō)一個(gè) List<String>類型被轉(zhuǎn)換為 List授滓。所有對(duì)類型變量的引用被替換成類型變量的上限(通常是 Object)

Java 的泛型支持僅在語(yǔ)法級(jí)別

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市肆糕,隨后出現(xiàn)的幾起案子般堆,更是在濱河造成了極大的恐慌,老刑警劉巖诚啃,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淮摔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绍申,警方通過(guò)查閱死者的電腦和手機(jī)噩咪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門顾彰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宪潮,“玉大人铃在,你說(shuō)我怎么就攤上這事。” “怎么了好乐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)企量。 經(jīng)常有香客問(wèn)我炸站,道長(zhǎng),這世上最難降的妖魔是什么吁讨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任髓迎,我火速辦了婚禮,結(jié)果婚禮上建丧,老公的妹妹穿的比我還像新娘排龄。我一直安慰自己,他們只是感情好翎朱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布橄维。 她就那樣靜靜地躺著尺铣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪争舞。 梳的紋絲不亂的頭發(fā)上凛忿,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音竞川,去河邊找鬼店溢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛委乌,可吹牛的內(nèi)容都是我干的逞怨。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼福澡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叠赦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起革砸,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤除秀,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后算利,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體册踩,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年效拭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暂吉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缎患,死狀恐怖慕的,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挤渔,我是刑警寧澤肮街,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站判导,受9級(jí)特大地震影響嫉父,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜眼刃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一绕辖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧擂红,春花似錦仪际、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吩抓。三九已至,卻和暖如春赴恨,著一層夾襖步出監(jiān)牢的瞬間疹娶,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工伦连, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雨饺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓惑淳,卻偏偏與公主長(zhǎng)得像额港,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歧焦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 本部分主要介紹:Java 的泛型移斩、泛型通配符使用的規(guī)則和注意事項(xiàng) 泛型總結(jié) 泛型是 JDK 1.5 出現(xiàn)的技術(shù),是...
    sshentree閱讀 785評(píng)論 0 2
  • [TOC] 泛型的使用 集合沒(méi)有泛型的時(shí)候绢馍,集合存放數(shù)據(jù)時(shí)都會(huì)丟失原來(lái)的類型向瓷,全部改為Object。這樣可以獲得良...
    洪孝崢閱讀 60評(píng)論 0 0
  • 集合沒(méi)有泛型的時(shí)候舰涌,集合存放數(shù)據(jù)時(shí)都會(huì)丟失原來(lái)的類型猖任,全部改為Object。這樣可以獲得良好的通用性瓷耙。但是取出的時(shí)...
    秋北_55a3閱讀 486評(píng)論 0 1
  • 泛型技術(shù)在C#和Java之中的使用方式看似相同朱躺,但實(shí)現(xiàn)上卻有著根本性的分歧,C#里面泛型無(wú)論在程序源碼中搁痛、編譯后的...
    zx_tree閱讀 149評(píng)論 0 0
  • 如果要針對(duì)每種類型的對(duì)象寫一個(gè)數(shù)據(jù)結(jié)構(gòu)长搀,則當(dāng)需要將其運(yùn)用到其他對(duì)象上時(shí),還要重寫這個(gè)數(shù)據(jù)結(jié)構(gòu)落追。如果使用了Objec...
    風(fēng)吹稻子閱讀 581評(píng)論 0 0