美文网首页
java基础-泛型

java基础-泛型

作者: graceLiZi | 来源:发表于2016-08-30 14:30 被阅读0次

    1.什么是泛型

    概括地讲,泛型就是我们在定义类、接口或方法的时候将某些引用到的类或接口参数化,这样定义的类、接口、方法就叫做泛型。这类似定义一般方法时,将传入的值参数化,不同的是泛型传的是类型,而方法传是具体的值。

    如,public interface List<E>就是将集合存放元素的类型参数化,即泛型。

    2.泛型的定义

    泛型类

    定义

    class Name<T1,T2,...,Tn>{/*...*/}

    泛型接口的定义和泛型类定义相似,将class换成interface即可。

    T1,T2,...,Tn 就是泛型的形参。例如:

    /**
     * @param <T> Box中存放至的类型,即形参
     */
    class Box<T> {
        // T stands for "Type"
        private T t;
    
        public void set(T t) {
            this.t = t;
        }
    
        public T get() {
            return t;
        }
    }
    

    泛型形参命名习惯

    • E-Element
    • K-Key
    • V-Value
    • T-Type
    • N-Number

    声明和实例化

    声明和实例化泛型类时,必须传入具体的类型。

    如:Box<Integer> intBox = new Box<Integer>();

    在Java SE 7及以后的版本,new后面<>内的类型可以省略,因为编译器从前面的声明,就已经能确定类型。这样我们可以用如下的写法,创建泛型类的实例Box<Integer> intBox = new Box<>();,这种写法叫做钻石写法,<>是不是像一颗钻石啊。

    泛型的原型

    泛型类省略了<T>,就叫做原型,如Box就是Box<T>的原型。只有泛型类(接口)有原型,非泛型类(接口)是没有原型的。

    原型之所以出现,是因为在JDK5以前,很多的类都没有泛型,为了实现泛型对原型的兼容。这样我们可以创建List的原型对象List list = new ArrayList(),使用原型就会丧失泛型的安全性。

    泛型方法

    定义

    <T1,T2,...,Tn> ReturnClassType methodName(T1 t1,T2 t2,...,Tn tn){/*...*/}

    注意以上定义省略了方法的修饰符,在实际定义泛型方法时根据情况补充修饰符,另外方法参数中也可以用非泛型类的参数。
    泛型方法的类型参数的有效范围仅为本方法内。静态方法、非静态方法以及构造方法都可以是泛型方法。

    如:

     public static <K,V> V get(Map<K, V> map, K key, V defaultValue) {
        if (key != null) {
            if (map != null && !map.isEmpty()) {
                V value = map.get(key);
                return (value == null) ? defaultValue : value;
            }
            return defaultValue;
        }
        return null;
    }
    

    有界类型参数

    有界类型参数,就是通过extends关键字限制类型参数只能为某一类型的子类,这是实现泛型算法的关键。如:

    public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
        int count = 0;
        for (T e : anArray)
            if (e.compareTo(elem) > 0)
                ++count;
        return count;
    }
    

    除了通过类来限制外,还可以使用接口来限制泛型,另外也可以通过类和接口共同来限制泛型。结构如下:

    class GenericTest<T extends TestClass & TestInterface1&...&TestInterfacen>{/*...*/}
    如果用类和接口共同来界定是,类必须写在前面。

    3.通配符?

    上界通配符<?extends ParentClass>

    上界通配符用于限制参数类型为某一明确的类及其子类。
    如:

    public static double sumOfList(List<? extends Number> list) {
        double s = 0.0;
        for (Number n : list)
            s += n.doubleValue();
        return s;
    }
    

    无界通配符<?>

    使用无界通配符,要求方法的逻辑只需要使用Object类的方法就可以实现,如:

    public static void printList(List<?> list) {
        for (Object elem: list)
            System.out.print(elem + " ");
        System.out.println();
    }
    

    下界通配符<?super ChildClass>

    下界通配符用于限制参数类型为某一明确的类及其父类,如。

    public static void addNumbers(List<? super Integer> list) {
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
    }
    

    通配符选择指南

    • 如果是输入参数变量,选用上界通配符。
    • 如果是输出参数变量,选用下界通配符。
    • 如果即是入参又是出参,不使用通配符

    子类、泛型与通配符的关系

    两个类存在父子关系,它们的泛型类之间是没有父子关系的,如Integer是Number的子类,但是Box<Integer>并不是Box<Number>的子类。但是可以通过通配符来建立关系,如List<? extends Integer>是List<? extends Number>的子类。


    imageimage
    imageimage

    4.泛型的好处

    1. 增加编译时的类型检查,避免运行时的类型转换异常。
    2. 提高代码的复用性,并能够复用算法。
    3. 无须再写强制类型转换的代码。

    https://docs.oracle.com/javase/tutorial/
    java/generics/types.html

    相关文章

      网友评论

          本文标题:java基础-泛型

          本文链接:https://www.haomeiwen.com/subject/cjgfettx.html