泛型最精準的定義:==參數化類型==。具體點說就是處理的數據類型不是固定的,而是能夠做爲參數傳入。定義泛型類、泛型接口、泛型方法,這樣,同一套代碼,能夠用於多種數據類型。(看到過有人面試問這個,感受這個解釋泛型最言簡意賅)java
雖然標識符號能夠隨意取,但爲了提升可讀性,通常遵循如下規則.面試
E — Element,經常使用在java Collection裏,如:List,Iterator,Set K,V — Key,Value,表明Map的鍵值對 N — Number,數字 T — Type,類型,如String,Integer等等數組
public class Generic<T>{
//key這個成員變量的類型爲T,T的類型由外部指定
private T key;
public Generic(T key) { //泛型構造方法形參key的類型也爲T,T的類型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值類型爲T,T的類型由外部指定
return key;
}
}
複製代碼
泛型的字母能夠隨意取,可是本身能夠規範點,Key,Value 能夠用(K, V)Element 能夠用E。bash
public interface Generator<T> {
public T next();
}
複製代碼
public < E > void printArray( E[] inputArray )
{
// 輸出數組元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
複製代碼
接收E類型以及其子類 被該泛型通配符限制的數組==只能取不能存==。由於該泛型爲其子類,不能肯定究竟幾級子類,所以不能加數據。只能取,取出的數據能保證必定能轉成E類型。ide
接收E類型以及其父類型。所以==只能存不能取==。若是要取的話只能是保證爲Object類型的數據,這樣沒意義。而存的話能存E以及E的子類。函數
無界通配符意味着可使用任何對象,所以使用它相似於使用原生類型。但它是有做用的,原生類型能夠持有任何類型,而無界通配符修飾的容器持有的是某種具體的類型。舉個例子,在List類型的引用中,不能向其中添加Object, 而List類型的引用就能夠添加Object類型的變量。post
在泛型代碼內部,沒法得到任何有關泛型參數類型的信息。
複製代碼
1 泛型類型不能顯式地運用在運行時類型的操做當中,例如:轉型、instanceof 和 new。由於在運行時,全部參數的類型信息都丟失了。ui
public class Erased<T> {
private final int SIZE = 100;
public static void f(Object arg) {
//編譯不經過
if (arg instanceof T) {
}
//編譯不經過
T var = new T();
//編譯不經過
T[] array = new T[SIZE];
//編譯不經過
T[] array = (T) new Object[SIZE];
}
}
複製代碼
2 泛型聲明的對象在類內部不能獲取某個類的特定方法。代碼以下this
class HasF {
public void f() {
System.out.println("HasF.f()");
}
}
public class Manipulator<T> {
private T obj;
public Manipulator(T obj) {
this.obj = obj;
}
public void manipulate() {
obj.f(); //沒法編譯 找不到符號 f()
}
public static void main(String[] args) {
HasF hasF = new HasF();
Manipulator<HasF> manipulator = new Manipulator<>(hasF);
manipulator.manipulate();
}
複製代碼
在這個例子中因爲泛型在代碼內部是沒法知道其確切類型,於是也就不能知道obj 是否有f()方法。上面這個問題解決方法能夠給T範型加入上邊界即 T extends HasF,這樣就解決這個問題了。spa
class Building {}
class House extends Building {}
public class ClassTypeCapture<T> {
Class<T> kind;
public ClassTypeCapture(Class<T> kind) {
this.kind = kind;
}
public boolean f(Object arg) {
return kind.isInstance(arg);
}
public static void main(String[] args) {
ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<Building>(Building.class);
System.out.println(ctt1.f(new Building()));
System.out.println(ctt1.f(new House()));
ClassTypeCapture<House> ctt2 = new ClassTypeCapture<House>(House.class);
System.out.println(ctt2.f(new Building()));
System.out.print(ctt2.f(new House()));
}
}
複製代碼
泛型參數的類型沒法用instanceof關鍵字來作判斷。因此咱們使用類類型來構造一個類型判斷器,判斷一個實例是否爲特定的類型。
Erased.java中不能new T()的緣由有兩個,一是由於擦除,不能肯定類型;而是沒法肯定T是否包含無參構造函數。
爲了不這兩個問題,咱們使用顯式的工廠模式:
interface IFactory<T> {
T create();
}
class Foo2<T> {
private T x;
public <F extends IFactory<T>> Foo2(F factory) {
x = factory.create();
}
}
class IntegerFactory implements IFactory<Integer> {
@Override
public Integer create() {
return new Integer(0);
}
}
class Widget {
public static class Factory implements IFactory<Widget> {
@Override
public Widget create() {
return new Widget();
}
}
}
public class FactoryConstraint {
public static void main(String[] args) {
new Foo2<Integer>(new IntegerFactory());
new Foo2<Widget>(new Widget.Factory());
}
}
複製代碼
經過特定的工廠類實現特定的類型可以解決實例化類型參數的需求。
通常不建議建立泛型數組。儘可能使用ArrayList來代替泛型數組。可是在這裏仍是給出一種建立泛型數組的方法。
public class GenericArrayWithTypeToken<T> {
private T[] array;
@SuppressWarnings("unchecked")
public GenericArrayWithTypeToken(Class<T> type, int sz) {
array = (T[]) Array.newInstance(type, sz);
}
public void put(int index, T item) {
array[index] = item;
}
public T[] rep() {
return array;
}
public static void main(String[] args) {
GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<Integer>(Integer.class, 10);
Integer[] ia = gai.rep();
}
}
複製代碼
這裏咱們使用的仍是傳參數類型,利用類型的newInstance方法建立實例的方式。
參考文章: