1. 程式人生 > >實習筆記(七)java泛型

實習筆記(七)java泛型

Java 中對於泛型方法的定義:

public <T> T getT(){

  .....相關程式碼;

}

其中我對<T>的理解就是申明只是一個泛型方法的標記,T是返回的型別。

對於泛型類的定義:

public class Type<T>{

  ....相關程式碼

}

上面寫的是關於泛型方法和泛型類的定義。這裡寫這篇部落格的主要目的是為了記錄<? extends T> 和 <? super T>的理解。

 

<? extends T>是上界萬用字元。邏輯上來說,一個可以往裡面放動物的容器,也可以往裡面放狗,因為狗是繼承了動物的,所以從

邏輯上來說,一個可以放狗的容器也應該是繼承一個可以放動物的容器的。但是Java中這是不對的。這時候就需要上界萬用字元來解決這個問題。

可以定義一個Content<? extends Animal> content,這個content容器裡面可以放任何Animal包括其子類。這使得容器Content之間也有

了一定的聯絡。但是其中的也有一定的副作用。Content類裡面有個getContent()方法,這個方法是不會影響使用的。因為對java編譯器來說,

裡面所有的東西都有一個相同的父親,那就是Animal。但是如果你想要使用setContent()方法,這時就會出現一個問題,問題是什麼呢?那就

是我只知道里面的型別是Animal以及Animal的派生類,但是無法確定具體的型別,是Dog或者Cat等。這裡的型別沒有具體給明,所以編譯器

在這裡只是給了一個佔位符,所以到後面往t裡面放Dog或者Apple的時候他都不知道是不是和Animal相匹配,所以這是不允許使用set的。下面

方法中的 public void setContent(List<T> content) 如果想可以set T包括T的子類的List的時候,可以這麼定義:

public void setContent(List<?extends T> content)。

 

<? super T>是下界萬用字元。其作用這好和上面的<? extends T>相反。Content<? super Animal> content 表示的是Animal 以及Animal

基類的容器,但不是Dog基類的容器。裡面的setContent()方法是可以正常使用的。因為它規定了最小粒度的下限,那就是Animal。但是它往外面

getContent()就比較費勁,因為他們公共的基類只有Object。所以取出來的內容只能用Object來裝。

 

所以這裡總結了一點就是如果一個內容他需要set的內容比較多,那就使用<? super T>。如若使用get的多一點,那就使用<? extends T>。

  • 泛型引數Class、Class<?>、Class<? extends xx>的對比

/**
 * Created by ypyue on 2017/6/19.
 */
public class Main2 {

    public static void main(String[] args) throws InstantiationExceptionIllegalAccessException {
        System.out.println("1-----------");
        Dog dog1 = creatNew1(Dog.class);
        System.out.println(dog1.name " is " + dog1.type"\n");

        System.out.println("2-----------");
        Animal ani1 = creatNew2(Cat.class);
        Cat cat1 = (Cat) ani1;
        System.out.println(cat1.name " is " + cat1.type "\n");

        System.out.println("3-----------");
        Object obj = creatNew3(Dog.class);
        Dog dog2 = (Dog) obj;
        System.out.println(dog1.name " is " + dog2.type "\n");

        System.out.println("4-----------");
        Object obj2 = creatNew4(Cat.class);
        Cat cat2 = (Cat) obj2;
        System.out.println(cat2.name " is " + cat2.type "\n");

        System.out.println("5-----------");
        Object obj3 = creatNew5(new Cat());
        Cat cat3 = (Cat) obj3;
        System.out.println(cat3.name " is " + cat3.type "\n");
    }

    /**
     * 此方法是一個非泛型類中的泛型方法,引數為Class<T>型別,可以傳入任何類,但是Class<T>將引數在函式內部的型別固定為 T類,使用clazz.newInstance(),返回的型別也為固定的 型別。
     傳入Dog.class, 函式中的 固定為Dog.class,函式返回的是Dog型別,不需要強制轉換為Dog型別
     (當然,函式返回型別也可以是Object型別,但是沒必要)
     */
   public static <TcreatNew1(Class<T> clazz) throws IllegalAccessExceptionInstantiationException {
        System.out.println(clazz);//列印具體傳入的型別。
        return clazz.newInstance();
    }

    /**
     * 此方法引數是Class<? extends Animal>,只能傳入Animal及其子類的型別,函式返回型別只能宣告為AnimalObject型別,
     如:傳入Cat.class,函式返回一個Animal的子類物件,需將此子類物件強制轉換為具體的子類(Cat)
     */
   public static Animal creatNew2(Class<? extends Animal> clazz) throws IllegalAccessExceptionInstantiationException {
        System.out.println(clazz);//列印具體傳入的型別。
        return clazz.newInstance();
    }

    /**
     * 此方法引數是Class,可傳入任何類,其返回只能宣告為Object類物件。
     如:傳入Dog.class, 返回的是Object型別的物件,需強制轉換為Dog型別的物件。
     */
   public static Object creatNew3(Class clazz) throws IllegalAccessExceptionInstantiationException {
        System.out.println(clazz);//列印具體傳入的型別。
        return clazz.newInstance();
    }

    /**
     * 傳入引數Class<?> 和 上一個方法傳入 Class 的區別還不是很清楚,其返回只能宣告為Object類物件。
     如:Cat.class, 返回的是Object型別的物件,需強制轉換為Cat型別的物件。
     */
    public static Object creatNew4(Class<?> clazz) throws IllegalAccessExceptionInstantiationException {
        System.out.println(clazz);//列印具體傳入的型別。
        return clazz.newInstance();
    }

    /**
     * 傳入Object型別的物件,返回也宣告為Object型別。
     */
    public static Object creatNew5(Object object) {
        System.out.println(object.getClass());//列印具體傳入的型別。
        return object;
    }
}

abstract class Animal {
    public String type "type = animal ";
}

class Dog extends Animal {
    public String name "name = gou";
}

class Cat extends Animal {
    public String name "name = mao";
}

/**
 * 這些方法,傳的引數宣告不同,其返回的宣告也必然要隨之不同。
 */

輸出:
1----------- class Dog name = gou is type = animal
2----------- class Cat name = mao is type = animal
3----------- class Dog name = gou is type = animal
4----------- class Cat name = mao is type = animal
5----------- class Cat name = mao is type = animal