天天看點

[JavaCore]JAVA中的泛型

JAVA中的泛型

【更新總結】

泛型就是定義在類裡面的一個類型,這個類型在編寫類的時候是不确定的,而在初始化對象時,必須确定該類型;這個類型可以在一個在裡定義多個;在一旦使用某種類型,在類方法中,那麼統一都必須使用該類型(比如出現T的,所有類方法都必須以T為一種類型);類和方法可以使用不同的類型(比如類中定義R,而方法可以定義S,兩者類型可以不一緻)。但是在接口中定義泛型方法時,類型必須通過類進行傳遞至方法,就是說方法聲明的類型必須與接口聲明一緻。

[寫在開始]

以前在博彥給微軟做外包的時候,做的是浏覽器的測試,接觸到C#相關知識點比較多,經常學習相關知識,對泛型有略微了解,但不深入,隻知道方法的參數可以為任意類型,前天看了篇文章,總結的比較好,一直都覺得泛型這東西很好,今天再對JAVA中的泛型總結總結。

[掃盲]

Java泛型(Generics)是JDK5開始引入的一個新特性,允許在定義類和接口的時候使用類型參數(Type Parameter)。聲明的類型參數在使用時用具體的類型來替換,現在泛型最主要的應用是在JDK5中的新集合類架構中,Map, List均有用到。其中的優點不言而喻,我們可以橫向擴充更多的類,缺點呢,其實也就是他的優點,因為這需要我們在使用泛型類的時候,要很清楚自己的代碼目地,不能使用錯誤的類型。

[看例子學習]

最基本的泛型類

package com.garinzhang.javabase.generic.e1;
/**
 * 最基本的泛型類,類型由自己定義
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Point<T> {
    private T var;
    public T getVar() {
        return var;
    }
    public void setVar(T var) {
        this.var = var;
    }
}
package com.garinzhang.javabase.generic.e1;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Point<String> p = new Point<String> ();
        p.setVar("coder");
        System.out.println(p.getVar());
    }
}      

多個泛型類型

package com.garinzhang.javabase.generic.e2;
/**
 * 多個泛型類型,一般多個最好是以靠近T的字母,如S,R等
 * @author Garin Zhang
 *
 * @param <T>
 * @param <S>
 */
public class Notepad<T, S> {
    private T key;
    private S value;

    public T getKey() {
        return this.key;
    }
    public S getValue() {
        return this.value;
    }
    public void setKey(T key) {
        this.key = key;
    }
    public void setValue(S value) {
        this.value = value;
    }
}
package com.garinzhang.javabase.generic.e2;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Notepad<String, Integer> p = new Notepad<String, Integer> ();
        p.setKey("coder");
        p.setValue(99999);
        System.out.println("key: " + p.getKey());
        System.out.println("value: " + p.getValue());
    }
}      

在方法參數中使用通配符"?"

package com.garinzhang.javabase.generic.e3;
/**
 * 該例子關鍵在main方法裡
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Info<T> {
    private T key;
    public T getKey() {
        return this.key;
    }
    public void setKey(T key) {
        this.key = key;
    }
    @Override
    public String toString() {
        return this.key.toString();
    }
}
package com.garinzhang.javabase.generic.e3;
/**
 * 在方法參數中使用通配符
 * @author Garin Zhang
 *
 */
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Info<String> i =  new Info<String>();
        i.setKey("coder");
        fun(i);
        Info<Integer> j = new Info<Integer>();
        j.setKey(9999);
        fun(j);
    }
    public static void fun(Info<?> temp) {
        System.out.println("Content: " + temp);
    }
}      

向上轉型失敗

package com.garinzhang.javabase.generic.e4;
/**
 * 該例子關鍵在main方法裡
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Info<T> {
    private T key;
    public T getKey() {
        return this.key;
    }
    public void setKey(T key) {
        this.key = key;
    }
    @Override
    public String toString() {
        return this.key.toString();
    }
}
package com.garinzhang.javabase.generic.e4;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Info<String> strEg = new Info<String>();
        Info<Object> objEg;
        // 編譯錯誤"Type mismatch: cannot convert from Info<String> to Info<Object>"
        // 向上轉型失敗,String -> Object
        // objEg = strEg;
    }
}      

泛型在接口中的使用

package com.garinzhang.javabase.generic.e5;
/**
 * 該例子關鍵在main方法裡
 * @author Garin Zhang
 *
 * @param <T>
 */
interface Info<T> {
    public T getVar();
}
package com.garinzhang.javabase.generic.e5;
/**
 * 泛型類
 * @author Garin Zhang
 *
 * @param <T>
 */
public class InfoImpl<T> implements Info<T> {
    private T var;
    public InfoImpl(T var) {
        this.setVar(var);
    }
    public void setVar(T var) {
        this.var = var;
    }
    public T getVar() {
        return this.var;
    }
}
package com.garinzhang.javabase.generic.e5;
/**
 * 非泛型類
 * @author Garin Zhang
 *
 * @param <T>
 */
public class InfoImpl1 implements Info<String> {
    private String var;
    public InfoImpl1(String var) {
        this.setVar(var);
    }
    public void setVar(String var) {
        this.var = var;
    }
    public String getVar() {
        return this.var;
    }
}
package com.garinzhang.javabase.generic.e5;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Info<String> strEg = new InfoImpl<String>("coder");
        System.out.println("Content: " + strEg.getVar());

        Info<String> strEg1 = new InfoImpl1("coder1");
        System.out.println("Content: " + strEg1.getVar());
    }
}      

通配符和extends, super的使用

package com.garinzhang.javabase.generic.e6;
/**
 * 該例子關鍵在main方法裡
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Info<T> {
    private T key;
    public T getKey() {
        return this.key;
    }
    public void setKey(T key) {
        this.key = key;
    }
    @Override
    public String toString() {
        return this.key.toString();
    }
}
package com.garinzhang.javabase.generic.e6;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Info<String> strEg =  new Info<String>();
        strEg.setKey("coder");
        // 編譯報錯"The method fun(Info<? extends Number>) in the type GenericExample is not applicable for the arguments (Info<String>)"
        // upTypeLimit(i);

        // 使用Integer,Number類型均可以
        Info<Integer> intEg = new Info<Integer>();
        intEg.setKey(9999);
        upTypeLimit(intEg);

        // 編譯報錯"The method downTypeLimit(Info<? super String>) in the type GenericExample is not applicable for the arguments (Info<Integer>)"
        // downTypeLimit(intEg);

        // 由于使用的是super,downTypeLimit隻能接收String本身和Object
        // 檢視了String的繼承關系,沒有繼承其他類,隻有Object
        downTypeLimit(strEg);

        Info<Object> objEg = new Info<Object>();
        objEg.setKey(999);
        downTypeLimit(objEg);
    }
    /**
     * <? extends T> 表示類型的上界,表示參數化類型的可能是T 或是 T的子類
     * @param temp
     */
    public static void upTypeLimit(Info<? extends Number> temp) {
        System.out.println("Content: " + temp);
    }

    /**
     * <? super T> 表示類型下界(Java Core中叫超類型限定),表示參數化類型是此類型的超類型(父類型),直至Object
     * 在此例中,表示T隻能為Object或String,因為String隻繼承于Object
     * @param temp
     */
    public static void downTypeLimit(Info<? super String> temp) {
        System.out.println("Content: " + temp);
    }
}      

方法泛型,方法裡面多個泛型

package com.garinzhang.javabase.generic.e7;
/**
 * 方法泛型,方法裡面多個泛型
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Info {
    /**
     * 格式:方法修飾付 <以逗号隔開的類型清單> 傳回值類型 方法名(參數清單)
     * 例如:public <T, S> T fun(T t, S s)
     * @param t
     * @param s
     * @return
     */
    public <T, S> T fun(T t, S s) {
        System.out.println(s.toString());
        return t;
    }
}
package com.garinzhang.javabase.generic.e7;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Info info = new Info();
        String str = info.fun("coder", "print second generic param");
        System.out.println(str);

        int i = info.fun(30, "print second param again");
        System.out.println(i);
    }
}      

 方法中傳入或傳回的泛型類型由調用方法時所設定的參數類型決定

package com.garinzhang.javabase.generic.e8;
/**
 * extends
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Info<T extends Number> {
    private T var;
    public T getVar() {
        return this.var;
    }
    public void setVar(T var) {
        this.var = var;
    }
    @Override
    public String toString() {
        return this.var.toString();
    }
}
package com.garinzhang.javabase.generic.e8;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Info<Integer> intEg = fun(30); // 這裡類型已經确定為Integer
        System.out.println(intEg.getVar());
    }
    /**
     * 方法中傳入或傳回的泛型類型由調用方法時所設定的參數類型決定
     * @param param
     * @return
     */
    public static <T extends Number> Info<T> fun(T param) {
        Info<T> temp = new Info<T>();
        temp.setVar(param);
        return temp;
    }
}      

 讓方法中傳入兩個參數類型保持一緻

package com.garinzhang.javabase.generic.e9;
/**
 * 檢視main
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Info<T> {
    private T var;
    public T getVar() {
        return this.var;
    }
    public void setVar(T var) {
        this.var = var;
    }
    @Override
    public String toString() {
        return this.var.toString();
    }
}
package com.garinzhang.javabase.generic.e9;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Info<String> i1 = new Info<String>();
        i1.setVar("Hello");

        Info<String> i2 = new Info<String>();
        i2.setVar("Coder");

        Info<Integer> i3 = new Info<Integer>();
        i3.setVar(999);

        add(i1, i2);

        //編譯錯誤“The method add(Info<T>, Info<T>) in the type GenericExample is not applicable for the arguments (Info<String>, Info<Integer>)”
        // add(i1, i3);
    }
    /**
     * 方法中傳入兩個參數類型必須一緻
     * @param param
     * @return
     */
    public static <T> void add(Info<T> i1, Info<T> i2) {
        System.out.println(i1.getVar() + ":" + i2.getVar());
    }
}      

泛型,可變參數,類似于javascript裡的Arguments對象

package com.garinzhang.javabase.generic.e10;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Integer i[] = fun(1, 2, 3, 4, 5, 6);
        fun2(i);
    }
    public static <T> T[] fun(T... arg) {
        return arg;
    }
    public static <T> void fun2(T param[]) {
        System.out.println("generic array: ");
        for(T t : param) {
            System.out.println(t + " ,");
        }
    }
}      

泛型嵌套:使用泛型類做為參數;根據傳回值類型确定傳回值

package com.garinzhang.javabase.generic.e11;
/**
 * 接受兩個泛型類型
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Info<T, V> {
    private T var;
    private V value;

    public T getVar() {
        return this.var;
    }
    public void setVar(T var) {
        this.var = var;
    }

    public V getValue(){
        return this.value;
    }
    public void setValue(V value) {
        this.value = value;
    }
    @Override
    public String toString() {
        return this.var.toString();
    }
}
package com.garinzhang.javabase.generic.e11;
/**
 * 接受1個泛型類型
 * @author Garin Zhang
 *
 * @param <T>
 */
public class Demo<S> {
    private S info;
    public Demo(S info) {
        this.setInfo(info);
    }
    public void setInfo(S info) {
        this.info = info;
    }
    public S getInfo() {
        return this.info;
    }
}
package com.garinzhang.javabase.generic.e11;
import java.util.List;
import com.google.common.collect.Lists;
public class GenericExample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Demo<Info<String, Integer>> d;
        Info<String, Integer> i;
        i = new Info<String, Integer>();
        i.setVar("Coder");
        i.setValue(999);
        d = new Demo<Info<String,Integer>>(i);
        System.out.println("Content: " + d.getInfo().getVar());
        System.out.println("Content: " + d.getInfo().getValue());


        System.out.println(query(1, 2, 3, 4, 5).toString());            // [1, 2, 3, 4, 5]
        // 警告"Type safety: A generic array of Object&Comparable<?>&Serializable is created for a varargs parameter"
        System.out.println(query(1, 2, 3, "StringType").toString());    // [1, 2, 3, StringType]
        System.out.println(query("I ", "am ", "a ", "coder").toString());// [I , am , a , coder]

        List<String> list = Lists.newArrayList("I ", "am ", "a ", "coder");
        System.out.println(list.toString());        // [I , am , a , coder]
    }
    /**
     * 通過傳回值确定泛型類型,這個方法裡面的傳回值類型,是由方法的定義自動生成的
     * @param elements
     * @return
     */
    public static <E> List<E> query(E... elements) {
        // https://github.com/exitsoft/exit-web-framework/commit/1d2f1098a2a4b6abab175b793e2308aa8bd0ea16.
        // import com.google.common.collect.Lists;
        //        <dependency>
        //            <groupId>com.google.guava</groupId>
        //            <artifactId>guava</artifactId>
        //            <version>16.0.1</version>
        //        </dependency>
        return Lists.newArrayList(elements);
    }
 }      

參考資料:

http://www.cnblogs.com/sharpxiajun/archive/2013/05/19/3087179.html

http://blog.csdn.net/jinuxwu/article/details/6771121

http://luckykapok918.blog.163.com/blog/static/2058650432012102341548827/

http://sharewind.iteye.com/blog/1622164

http://love-love-l.blog.163.com/blog/static/21078304201081312858230/

http://www.cnblogs.com/panjun-Donet/archive/2008/09/27/1300609.html

Thinking in Java

路慢慢其休遠羲,吾将上下而求所