java基础-泛型

2016-08-30  本文已影响0人  graceLiZi

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;
    }
}

泛型形参命名习惯

声明和实例化

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

如: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

上一篇下一篇

猜你喜欢

热点阅读