首页 > 代码库 > Java核心 --- 泛型

Java核心 --- 泛型

CoreJava 泛型

java泛型的出现避免了强制类型转换,便于代码更好的被阅读

本文的写作参照了张孝祥的泛型介绍:http://www.itcast.cn/news/dbfd20f1/f4b1/412d/9b40/c1a81b8bf1da.shtml

更多疑问请参考:http://www.vaikan.com/java-generics-quick-tutorial/

1.可以接收类型参数的类型在接受类型参数后变为泛型,但是,虽然是不同的泛型但是还是相同的类型

package com.yuki.generic;import java.util.Vector;/** * 同一个类型的不同的泛型 * Vector<Integer>和Vector<Boolean>是同一个类型的不同泛型 *  * @author yuki * */public class Demo1 {    public static void main(String[] args) {                Vector<Integer> vi = new Vector<>();        Vector<Boolean> vb = new Vector<>();                vi.add(1);        vb.add(true);                boolean same = vi.getClass() == vb.getClass();                System.out.println("same = " + same);    }}

执行结果如下:

same = true

2.可以通过反射跳过泛型的类型参数的限制

package com.yuki.generic;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;/** * 反射调用泛型方法 *  * ArrayList<E>中的E表示的是一个类型参数或类型变量 * ArraList<Integer>称为已参数化的类型 * ArraList<Integer>中的Integer称为类型参数的实例或实际类型参数 * ArraList<Integer> 读作 ArraList type of Integer * ArrayList 称为原始类型 *  * @author yuki * */public class Demo2 {        public static void main(String[] args) throws Exception {        // List<Integer> l = new ArrayList<Integer>();        // 下面的写法也是可以的        List<Integer> l = new ArrayList<>();                // 规定存放整数对象的序列不能存放字符串        // list.add("i am string"); // error!                Method m = l.getClass().getMethod("add", Object.class);        m.invoke(l, "abc");                System.out.println("l.get(0) = " + l.get(0));                // 不能创建参数化类型的数组,Cannot create a generic array        // List<Object>[] l2 = new ArrayList<Object>[10]; // error!    }    }

执行结果如下:

l.get(0) = abc

3.问号?可以作为泛型的通配符,发可以匹配任意类型, 但是形参上的参数引用失去了泛型的信息

package com.yuki.generic;import java.util.ArrayList;import java.util.Collection;import java.util.List;public class Demo3 {    public static void main(String[] args) {                List<Integer> l = new ArrayList<>();        l.add(1);        l.add(2);                printCollection(l);    }        // --- 没有使用泛型 ---    // public static void printCollection(Collection collection){    // --- 泛型类型必须为Collection<Object>,不能传递类似Collection<Integer>的参数 ---    // public static void printCollection(Collection<Object> collection){    // ? 是通配符,表示可以接受任意类型    public static void printCollection(Collection<?> c){        // 不能调用与类型有关的方法        // c.add(1); // error!        final int SIZE = c.size();        int i = 0;        for(Object o : c){            System.out.println("c : " + i++ + " in " + SIZE + " -> " + o);        }    }}

运行结果如下:

c : 0 in 2 -> 1c : 1 in 2 -> 2

4.静态函数Class.forName返回的参数类型是Class<?>,应为传入的类名只是它的参数

package com.yuki.generic;public class Demo4 {public static void main(String[] args) throws Exception {        // 它返回的是Class<?>        // Class<Number> y = Class.forName("java.lang.String");        Class<?> y = Class.forName("java.lang.String");

     System.out.println("y = " + y); }}

运行结果如下:

y = class java.lang.String

5.泛型方法的定义,它接受的参数和它的返回值会搜索继承树上最近的一个分支点

比如说,猫和狗它们的最小父类是犬科动物,而不是脊椎动物

package com.yuki.generic;public class Demo5 {    @SuppressWarnings("unused")    public static void main(String[] args) {                Integer i = add(3, 5);                // Float n = add(3.5, 5); // error!        // Float 和 Integer 的父类是 Number        Number n = add(3.5, 5);        Object o = add(3, "abc");    }        // 在返回方法前,获取方法的类型参数    private static <T> T add(T x, T y){        System.out.println("wake up : x = " + x + ", y = " + y);        return null;    }}

运行结果如下:

wake up : x = 3, y = 5wake up : x = 3.5, y = 5wake up : x = 3, y = abc

6.定义一个一个泛型的方法,int[]已经是引用类型而不是基本类型,所以不能自动封箱

package com.yuki.generic;public class Demo6 {    public static void main(String[] args) {                String[] a = swap(new String[]{"abc", "xyz", "uvw"}, 1, 2);        StringBuilder sb = new StringBuilder();        for(String s : a){            sb.append(s + ‘,‘);        }        System.out.println(sb);                // 泛型必须是引用类型,不能使基本类型        // int[] 已经是对象了,所以不能自动封箱        // swap(new int[]{1, 2, 3, 4, 5}, 3, 4); // error!    }        /**     * 定义泛型是可以限定类型     * 限定它必须实现某接口或实现某类,用and连接     * <T extends Serializable & Cloneable>     *      * 可以抛出泛型的异常     * <T extends Exception> void methodName() throws T     *      * 声明多个泛型之间用,分割     */    private static <T> T[] swap(T[] a, int i, int j){        T temp = a[i];        a[i] = a[j];        a[j] = temp;                return a;    }    }

运行结果如下:

abc,uvw,xyz,

7.自动类型转换的泛型方法,虽然可以不必这么麻烦的。。。

package com.yuki.generic;public class Demo7 {    public static void main(String[] args) {                Object o = "abc";        String s = autoConvert(o);                System.out.println("s = " + s);    }    @SuppressWarnings("unchecked")    private static <T> T autoConvert(Object o){        return (T)o;    }    }

运行结果如下:

s = abc

8.当参数中有两个相同的泛型类型引用时,这里, 第一个匹配的参数类型确定方法的泛型类型

package com.yuki.generic;import java.util.Collection;import java.util.Date;import java.util.Vector;public class Demo8 {    public static void main(String[] args) {        // 正确        copy1(new Vector<String>(), new String[10]);                // Date和String取共同的最小父类        copy2(new Date[10], new String[20]);                // String不是Date的子类        // copy1(new Vector<Date>(), new String[10]); // error!            }        //    private static <T> void copy1(Collection<T> c, T[] a){            }    private static <T> void copy2(T[] c, T[] a){            }}

 

9.定义泛型类,类的实例方法可以使用运行实例化的泛型类,但是,静态方法与类的实例,所以需要定义为泛型方法

程序的入口:Demo9

package com.yuki.generic;public class Demo9 {    public static void main(String[] args) {                GenericSample<String> gs = new GenericSample<>();                // 参数类型不匹配        // gs.add(3); // error!                gs.add("hello, generic");        String s = gs.look();                System.out.println("s = " + s);    }    }

使用到的类:GenericSample

package com.yuki.generic;// 类级别的泛型public class GenericSample<E> {    private E e;        public void add(E e){        this.e = e;    }        public E look(){        return e;    }        // 静态方法不能使用类的实例才能使用的泛型    // public static void staticMethod(E e) { }        // 这里使用的是方法级别的泛型    public static <E> void staticMethod(E e) { }}

运行结果如下:

s = hello, generic

10.怎样知道方法的泛型参数中可以容纳的泛型参数类型呢?

程序入口:Demo10

package com.yuki.generic;import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.Date;import java.util.List;import java.util.Vector;public class Demo10 {    public static void main(String[] args) throws Exception {                GenericParameter<Date> gp = new GenericParameter<>();                // 怎样知道集合中所装的实例类型        Class<?> clazz = gp.getClass();        Method method = clazz.getMethod("applyVector", Vector.class);                // Type是Class的子类,它的其中一个子接口是ParameterizedType        Type[] types = method.getGenericParameterTypes();        ParameterizedType pType = (ParameterizedType) types[0];                // 得到泛型的类型        Type t = pType.getRawType();        // 得到泛型参数的类型        Type[] ta = pType.getActualTypeArguments();                System.out.println("t = " + t);        System.out.println("ta[0] = " + ta[0]);                Method method2 = clazz.getMethod("applyList", List.class);        ParameterizedType pType2 = (ParameterizedType) method2.getGenericParameterTypes()[0];        System.out.println("rawType = " + pType2.getRawType());        System.out.println("actualTypeArguments[0] = " + pType2.getActualTypeArguments()[0]);    }}

使用到的类:GenericParameter<E>

package com.yuki.generic;import java.util.Date;import java.util.List;import java.util.Vector;public class GenericParameter<E> {        public void applyVector(Vector<E> v){        // 我们不知道参数列表中参数的类型,        // 但是当把变量交给一个方法去使用时        // 可以知道方法所接受参数的实际类型    }    public void applyList(List<Date> v){    }}

运行结果如下:

t = class java.util.Vectorta[0] = ErawType = interface java.util.ListactualTypeArguments[0] = class java.util.Date

跟多好文请看:http://www.cnblogs.com/kodoyang/

Thanks!