泛型
oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
在Java中静秆,泛型的引入是為了在編譯時提供強類型檢查和支持泛型編程竣况。為了實現(xiàn)泛型区赵,Java編譯器應用類型擦除實現(xiàn):
1受楼、 用類型參數(shù)(type parameters)的限定(如果沒有就用Object)替換泛型類型中的所有類型參數(shù)虏冻。
2贬墩、 需要保持類型安全的時候插入類型轉(zhuǎn)換(隱含插入)
3呀闻、 在extened 泛型類型中生成橋方法來保證多態(tài)性
類型擦除確保不會為已參數(shù)化了的類型(paramterized types)產(chǎn)生新類精肃,這樣泛型能保證沒有運行時的負載秤涩。泛型的好處是在編譯的時候檢查類型安全,減少運行時的問題司抱;避免強制轉(zhuǎn)換的麻煩筐眷;
特性
只在編譯階段有效。在編譯過程中习柠,正確檢驗泛型結(jié)果后匀谣,會將泛型的相關(guān)信息擦除
如:
public class MyClass {
private static List<String> list1 = new ArrayList<>();
private static List<Integer> list2 = new ArrayList<>();
public static void main(String args[]){
list1.add("aaaa");
list2.add(11);
System.out.println("----list1------>" + list1.getClass());
System.out.println("----list2------>" + list2.getClass());
System.out.println("泛型類型是否相同-->" + list2.getClass().equals(list1.getClass()));
}
}
輸出結(jié)果:
----list1------>class java.util.ArrayList
----list2------>class java.util.ArrayList
泛型類型是否相同-->true
在編譯之后程序會采取去泛型化的措施照棋。也就是說Java中的泛型,只在編譯階段有效武翎。在編譯過程中必怜,正確檢驗泛型結(jié)果后,會將泛型的相關(guān)信息擦出后频,并且在對象進入和離開方法的邊界處添加類型檢查和類型轉(zhuǎn)換的方法梳庆。也就是說,泛型信息不會進入到運行時階段卑惜。
對此總結(jié)成一句話:泛型類型在邏輯上看以看成是多個不同的類型膏执,實際上都是相同的基本類型。
擦除規(guī)則
JVM并不知道泛型的存在露久,因為泛型在編譯階段就已經(jīng)被處理成普通的類和方法更米;
處理機制是通過類型擦除,擦除規(guī)則:
若泛型類型沒有指定具體類型毫痕,用Object作為原始類型征峦;
若有限定類型< T exnteds XClass >,使用XClass作為原始類型消请;
若有多個限定< T exnteds XClass1 & XClass2 >栏笆,使用第一個邊界類型XClass1 XClass2作為原始類型
如下例:
測試目錄結(jié)構(gòu)
├── MyClass.java //測試類
├── parent
│ ├── IOne.java //接口1
│ ├── ITwo.java //接口2
│ └── ParentOne.java //父類
├── sun
│ ├── Sun.java
│ └── SunOne.java
├── Test.java
├── TestOne.java
└── TestTwo.java
定義測試類
package com.example.test;
import com.example.test.sun.Sun;
import com.example.test.sun.SunOne;
public class MyClass {
public static void main(String args[]){
//無限定
Test test = new Test();
test.setT("test");
//< T exnteds XClass > 限定
TestOne testOne = new TestOne();
testOne.setT(new SunOne());
//多個限定< T exnteds XClass1 & XClass2 >
TestTwo testTwo = new TestTwo();
testTwo.setT(new Sun());
System.out.println("----test------>" + test.getClass());
System.out.println("----testOne------>" + testOne.getClass());
System.out.println("----testTwo------>" + testTwo.getClass());
}
}
無限定
package com.example.test;
/**
* T 無限定
* @param <T>
*/
public class Test<T> {
/**
* T 最終等同于
* private Object t;
*/
private T t;
public void setT(T t) {
this.t = t;
}
}
單個限定
package com.example.test;
import com.example.test.parent.ParentOne;
/**
* T 傳入的類型必須繼承于ParentOne
* @param <T>
*/
public class TestOne<T extends ParentOne> {
private T t;
public void setT(T t) {
this.t = t;
}
}
package com.example.test.sun;
import com.example.test.parent.ParentOne;
public class SunOne extends ParentOne {
}
package com.example.test.parent;
public class ParentOne {
}
多個限定 類實現(xiàn)兩個接口
package com.example.test;
import com.example.test.parent.IOne;
import com.example.test.parent.ITwo;
/**
* T 類型 必須繼承IOne ITwo 接口
* @param <T>
*/
public class TestTwo<T extends IOne & ITwo> {
private T t;
public void setT(T t) {
this.t = t;
}
}
package com.example.test.sun;
import com.example.test.parent.IOne;
import com.example.test.parent.ITwo;
public class Sun implements IOne,ITwo {
}
package com.example.test.parent;
public interface ITwo {
}
package com.example.test.parent;
public interface IOne {
}
泛型中占位符T和?區(qū)別
“<T>"和"<?>",首先要區(qū)分開兩種不同的場景:
- 第一臊泰,聲明一個泛型類或泛型方法蛉加。
- 第二,使用泛型類或泛型方法缸逃。
- 類型參數(shù)“<T>”主要用于第一種针饥,聲明泛型類或泛型方法。
- 無界通配符“<?>”主要用于第二種需频,使用泛型類或泛型方法
泛型的限定:
? extends E:接收E類型或者E的子類型丁眼。
?super E:接收E類型或者E的父類型昭殉。
簡單例子
package com.example.test;
import java.util.ArrayList;
import java.util.List;
public class MyClass {
private static List list1 = new ArrayList();
private static List<String> list2 = new ArrayList();
public static void main(String args[]){
list1.add("aaa");
list1.add(33);
list2.add("bbbb");
list2.add("cccc");
for (int i =0 ;i<list1.size();i++){
System.out.println("---------->" + list1.get(i));
}
System.out.println("-----#############-----");
for (int i =0 ;i<list2.size();i++){
System.out.println("---------->" + list2.get(i));
}
}
}
輸出
---------->aaa
---------->33
-----#############-----
---------->bbbb
---------->cccc
一個限定類型苞七,只能add String
另一個,可添加多種類型的數(shù)據(jù)
//使用通配符饲化?
SuperClass<?> sup = new SuperClass<String>("例子");
sup = new SuperClass<Student>(new Student());
sup = new SuperClass<Teacher>(new Teacher());
//不使用通配符
SuperClass<String> sup1 = new SuperClass<String>("lisi");
SuperClass<Student> sup2 = new SuperClass<Student>(new Student());
SuperClass<Teacher> sup3 = new SuperClass<Teacher>(new Teacher());