【Java基础知识】泛型详解

1.泛型的概念:

泛型是Java SE 1.5的新特性,泛型的本质参数化类型,即所操作的数据类型被指定为一个参数。

2.使用泛型的优点:

(1)安全简单,提高代码重用率,在编译的时候检查类型安全,并且所有的强制类型转化都是自动和隐式的;

(2)类型安全,向后兼容,层次清晰,性能较高。

3.元组类库(出处:《Thinking Java》)

(1)定义:元组指将一对对象直接打包存储于其中的一个单一对象,这个容器对象允许读取其中元素,但不允许向其中放入新的对象;

(2)元组可以具有任意长度,元组中的对象可以是任意不同类型。

例:

//一个1维元组,它持有1个对象
class OneTuple<A> {
    //code
}

//一个2维元组,它持有两个对象
class TwoTuple<A,B> {
    //code
}

4.定义简单泛型

(1)泛型类:具有一个或多个类型变量的类

public class Pair<T> {
    private T first;
    private T second;

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return this.first;
    }

    public void setFirst(T newValue) {
        this.first = newValue;
    }
}

(2)泛型方法:

例:

//普通泛型方法
public class ArrayAlg {
    //...表示可变参数
    public <T> T getMiddle(T... a) {
        return a[a.length/2];
    }
}

//集合泛型方法
class ArrayListTest {
    public <T> List<T> list() {
        return new ArrayList<T>();
    }
}

(3)泛型接口
例:

public interface Generator<T> {
    T next();
}

(4)泛型应用于匿名内部类
例:

public class Customer {
    public  Generator<Customer> clerk() {
        return new Generator<Customer>() {
            @Override
            public Customer next() {
                return new Customer();
            }
        };
    }
}

5.泛型的擦除

(1)定义;
java字节码中不包含有泛型的类型信息。编译器在编译阶段去掉泛型信息,在运行的时候加上类型信息。

(2)不同类型的擦除

例:

public class ErasedTypeEquairalence{
    public static void main(String[] args) {
        Class c1 = new ArrayList<String>().getClass();
        Class c2 = new ArrayList<Integer>().getClass();
        System.out.println(c1 == c2);
    }
}

//输出结果: true

(3)重载中的类型擦除

例:

class HoldItem <T,V>{

    public void f(List<T> t) {} // error 编译器报错

    public void f(List<V> v) {}

    public void f(List<T> t,List<V> v) {}
}

6.泛型的边界

(1)限定类型:< T extends Comparable & Serializable>

由于泛型有擦除行为,所以只能调用Object的toString( ),equals( ),hashCode( )……方法,但若加上限制,
例:< T extends Dog> 就可以使用Dog类中的方法了。

(2)自限定类型: < T extends Access < T >>

若定义一个类F
class F extends Access< u > { }
这个U必须是Access的子类(即:u必须与Access有关)

7.通配符

(1)有限制的通配符

List < ? extends Fruit> 子类型通配符
List < ? super class> 超类型通配符

*生产者消费者模型
助记符:PESC (produce - extends consumer - super)

  • 如果想从列表中读取T类型的元素,则需要将这个列表声明成< ? extends T>,之后就不能往该列表中添加任何元素。

  • 如果想把T类型的元素加入到列表中,则需要把这个列表声明成< ? super T>,之后就不能从中读取元素。

  • 如果一个列表即要生产,又要消费,你不能使用泛型通配符声明列表,比如List < Integer >。

例:

    public <T extends Dog> void get1(List<T extends Dog> list){
        list.get(0);
    }

    //error
    public <T extends Dog> void set1(List<T extends Dog> list, Dog dog){
        list.add(dog);
    }

    //error
    public <T super Cat> void get2(List<T super Cat> list){
        list.get(0);
    }

    public <T super Cat> void set2(List<T super Cat> list, Cat cat){
        list.add(cat);
    }

例2:Collections类的copy方法就是典型的PECS模型,下面是copy方法的源码

/**
     * Copies all of the elements from one list into another.  After the
     * operation, the index of each copied element in the destination list
     * will be identical to its index in the source list.  The destination
     * list must be at least as long as the source list.  If it is longer, the
     * remaining elements in the destination list are unaffected. <p>
     *
     * This method runs in linear time.
     *
     * @param  <T> the class of the objects in the lists
     * @param  dest The destination list.
     * @param  src The source list.
     * @throws IndexOutOfBoundsException if the destination list is too small
     *         to contain the entire source List.
     * @throws UnsupportedOperationException if the destination list's
     *         list-iterator does not support the <tt>set</tt> operation.
     */

    public static <T> void copy(List<? super T> dest, List<? extends T> src) {
        int srcSize = src.size();
        if (srcSize > dest.size())
            throw new IndexOutOfBoundsException("Source does not fit in dest");

        if (srcSize < COPY_THRESHOLD ||
            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
            for (int i=0; i<srcSize; i++)
                dest.set(i, src.get(i));
        } else {
            ListIterator<? super T> di=dest.listIterator();
            ListIterator<? extends T> si=src.listIterator();
            for (int i=0; i<srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    }

(2)无界通配符 < ? >

8.约束与局限性

(1)不能用基本数据类型实例化类型参数
(2)运行时类型查询只适用于原始类型
(3)不能创建参数化类型的数组

例:

Pair<String>[] table = new Pair<String> [10];   //error

解决方法:
*使用ArrayList< Pair < String > >
*使用工具类 Arrays.asList()

(4)Varargs警告

抑制警告:@SuppressWarnings(“unchecked”) 或 safe Varargs

(5)不能实例化类型变量
(6)泛型类的静态上下文中类型变量无效
(7)不能抛出或捕获泛型类的实例
(8)防范擦除后的冲突




本人才疏学浅,如有错误,请指出~
谢谢!

你可能感兴趣的:(java,泛型)