java泛型剖析

shuaishuai3409發表於2016-08-26

一 java泛型是什麼?泛型的好處是啥?
那些擁有Java1.4或更早版本的開發背景的人都知道,
1> 在集合中儲存物件並在使用前進行型別轉換是多麼的不方便。泛型防止了那種情況的發生。
2> 它提供了編譯期的型別安全,確保你只能把正確型別的物件放入集合中,避免了在執行時出現ClassCastException。
二 泛型類
當類中操作的引用資料型別不確定的時候,就用泛型類。

public class Tool{
    public T obj;
    public T getObject(){
        return obj;
    }
    public void setObject(T str){
        System.out.println("111");
        this.obj=str;
    }

}
public class Car{
    public Car() {
    super();
    }
}
public class Bus {
    public Bus() {
    super();
    }
}
public class GenericDemo {
    public static void main(String[] args) {

    Tool<Car>tool=new Tool<Car>();
    tool.setObject(new Car());
    Car car=tool.getObject();
    tool.setObject(New Bus());//wrong
    }
}

某類操作不確定的引用資料型別,就用泛型類。沒有泛型之前,用Object,即Tool類如下:

public class Tool{

    public Object obj;

    public Object getObject(){
        return obj;
    }
    public void setObject(Object str){
        System.out.println("111");
        this.obj=str;
    }

}
public class GenericDemo{
    Tool  tool=new Tool ();
    tool.setObject(new Car());
    tool.setObject(new Bus());
    Car car=(Car)tool.getObject();}//需要強轉。就和ArrayList加泛型效果一樣,可在編譯期檢查。

這樣的話,就可以往裡新增任何物件,但是不安全。使用泛型類將執行時的安全檢查轉換到了編譯時期,避免了強轉的麻煩。
三 泛型方法
我們的目標是想在呼叫show函式時,能夠分別輸出String和Integer結果,而不是傳給不同引數的show函式。

public class Car<T>{
    public int viechle;
    public String battery;
    public Car(int viechle, String battery) {
        super();
        this.viechle = viechle;
        this.battery = battery;
    }
    public void show(String str){
        System.out.println(str);
    }

    public void show1(Object str){
        System.out.println(str);
    }
    public void show2(T str){
        System.out.print(str);
    }
    public <E> void show3(E str){
    }
}
<pre name="code" class="java">public class GenericDemo {
    public static void main(String[] args) {

        Car<String>car=new Car<String>();
        car.show3("d23");
        car.show3(3);
                car.show3(new Integer(3));
    }

}

public class Car<T>{
    public int viechle;
    public String battery;
    public Car(int viechle, String battery) {
        super();
        this.viechle = viechle;
        this.battery = battery;
    }
    public void show(String str){
        System.out.println(str);
    }

    public void show1(Object str){
        System.out.println(str);
    }
    public void show2(T str){
        System.out.print(str);
    }
    public <E> void show3(E str){
    }
}
public class GenericDemo {
    public static void main(String[] args) {

        Car<String>car=new Car<String>();
        car.show3("d23");
        car.show3(3);
                car.show3(new Integer(3));
    }

}

當呼叫show1方法時,是可以實現我們的目標的,通過向上轉型,Object可以轉換為String和Integer型別。當呼叫show2方法時,由於Car已經定義為String型別,即T被轉換為String型別,這樣在呼叫show2方法時,只能輸出字串型別,輸出整數型別就會提示錯誤。當然我們還有一種方法,就是使用泛型函式show3,這樣就可以根據需要,在執行時給定輸入型別,達到輸入啥型別輸出啥型別的效果。
四 泛型介面
將泛型定義在介面上,實現介面的類要給出具體的型別。

public interface Inter<T> {
    public <Q> void show(Q str);//泛型函式,依然適用於輸出任何型別的引數。</span>
    public void show2(T str);

}
public class InterClass2 implements Inter<String> {//實現介面時,要在介面處(Inter)和實現函式處(show2)給出具體的型別。這樣main函式中就可以放心的往裡放String型別字串。

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        InterClass2 inter=new InterClass2();
        inter.show2("2");
    }

    @Override
    public void show2(String str) {
        // TODO Auto-generated method stub
        System.out.println(str);
    }

}
---------------------另外一種實現方式---------------------------------------------
public class InterClass<T> implements Inter<T> {//實現介面時,不給出具體型別,而是在main函式中,通過建立物件,確定泛型的具體型別。

    public void show2(T str) {
        // TODO Auto-generated method stub
        System.out.println(str);
    }
    public static void main(String[] args) {
    InterClass<Integer>inter=new InterClass<Integer>();
    inter.show2(2);}}

五 萬用字元
顧名思義,通通都能匹配的符號,用?來接收任何未知型別。以列印集合元素為例,我有ArrayList、ArrayList、HashSet三個集合,想通過printCollection函式,往裡傳啥型別就輸出該型別所有元素。–可以用萬用字元來實現。

public class PrintColl {

    public static void printCollection(Collection<?>col){//如果只是ArrayList<String>和HashSet<String>集合,可用Collection<String>col方式(抽取共性)。但涉及到List和Set集合,並且有String和Integer不同型別,就得先抽取List和Set的共性:Collection,然後用萬用字元?表示String和Integer。
        Iterator<?>it=col.iterator();
        System.out.print(it.next());
    }
    public static void main(String[] args){
        ArrayList<String>a1=new ArrayList<String>();
        ArrayList<String>a2=new ArrayList<String>();
        HashSet<String>a3=new HashSet<String>();
        printCollection(a1);
        printCollection(a2);
        printCollection(a3);//這樣的話,能全部通過編譯,一次輸出不同型別。
    }
}
-------------------------------------------------------------------------------------
//其實printCollection函式,可用泛型函式實現相同功能。
public static <T> void printCollection(T str){
    Iterator<T>it=col.iterator();
    System.out.print(it.next());
 }

六 泛型上下限
我有兩個類Person和Dog,類Student繼承了Person類。現在我想實現這樣的功能:在呼叫printCollection函式時只列印Person及其子類物件,而不是一股腦統統的都列印出來。—-上(下)限。

public class Person {
    String name;
    int age;
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

}
public class Student extends Person {

    public Student(String name, int age) {
        super(name, age);
        // TODO Auto-generated constructor stub
    }

}
public class Dog {
    int age;
    public Dog(int age){
        this.age=age;
    }

}
public class PrintColl {

    public static void printCollection(Collection<? extends Person>col){
        Iterator<? extends Person>it=col.iterator();
        Person p=it.next();//確定上下限後,就可以用父類Person來接收所有子型別了,多好,將執行時的問題轉換到了編譯期。
         System.out.print(p);}
    public static void main(String[] args){
    ArrayList<Person>a1=new ArrayList<Person>();//ArrayList<Person>a1=new ArrayList<Student>()這樣是不可以的,宣告時集合中只能放Person物件,實體卻把Student放進去了,不能同一代表。同樣,反過來也不行,不能把實體Person放到Student的集合中去。兩邊泛型得匹配。
ArrayList<Dog>a2=new ArrayList<Dog>();
HashSet<Student>a3=new HashSet<Student>();
printCollection(a1);
//printCollection(a2);//新增a2就會出現問題,因為只能放Person及其子類。
printCollection(a3);}
}


------------在通過jdk兩個例子解釋下上下限-----------------------------------
Interface Collection<E>{
boolean addAll(Collection<?extends E>coll);//這樣寫,我可以往集合裡新增E及其子類元素。如果是addAll(Collection<E>就只能往裡新增E類元素,擴充套件性不強)
}
-----------------------------------------------------------------------------------------------------------------------------
class TreeSet<E>{
        TreeSet(Comparator<? super E>comparator);//若是TreeSet(Comparator<E>comparator)就只能用E類的比較器;若寫成這種形式(下限),E的子類也可以用父類的比較器。
}

相關文章