【Java基础】泛型

概述

什么是泛型?为什么要使用泛型

泛型,即“参数化类型”,就是将类型有原来的具体的类型参数化。

参数的本质就是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别称为泛型类、泛型接口、泛型方法。

泛型的使用

1. 泛型类

public class Box<T> {
	private T t;

	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}
	
	public static void main(String[] args) {
		Box<String> box = new Box<>();
		box.setT("123");
		System.out.println(box.getT());
	}
}

2. 泛型接口

public interface Iterable<T> {
    Iterator<T> iterator();
}

3. 泛型方法

public <A> boolean equals(A a1, A a2) {
	return a1.equals(a2);
}

边界符

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

通配符

<? extends T>

List<? extends Object> list1 = new ArrayList<Object>();
List<? extends Object> list2 = new ArrayList<String>();
List<? extends Object> list3 = new ArrayList<Integer>();

<? super T>

List<? super Integer> list4 = new ArrayList<Integer>();
List<? super Integer> list5 = new ArrayList<Number>();
List<? super Integer> list6 = new ArrayList<Object>();

List中的通配符

  • 对于<? extends T>,只能从List里面get元素,不能add元素
  • 对于? super T>,只能从List里面add元素,不能get元素
Collections类中的copy方法:

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

类型擦除

其实泛型也是Java的一种语法糖

反编译上述Box类,将会得到如下代码,会利用Object类和强转型。

public class Box {

   private Object t;


   public Object getT() {
      return this.t;
   }

   public void setT(Object t) {
      this.t = t;
   }

   public boolean equals(Object a1, Object a2) {
      return a1.equals(a2);
   }

   public static void main(String[] args) {
      Box box = new Box();
      box.setT("123");
      System.out.println((String)box.getT());
   }
}
Class<?> class1 = new ArrayList<String>().getClass();
Class<?> class2 = new ArrayList<Integer>().getClass();
System.out.println(class1 == class2);// true

不允许创建泛型数组

ArrayList<String>[] ls = new ArrayList<String>[10]; // Cannot create a generic array of ArrayList<String>

不能利用类型参数创建实例

public static <E> void append(List<E> list) {
	E elem = new E(); // Cannot instantiate the type E
	list.add(elem);
}

如果想要类型参数创建实例,可以利用class类

	public static <E> void append(List<E> list, Class<E> cls) throws InstantiationException, IllegalAccessException {
		E elem = cls.newInstance();
		list.add(elem);
	}

无法对泛型代码直接使用instanceof关键字

// Cannot perform instanceof check against parameterized type
// ArrayList<Integer>.
// Use the form ArrayList<?> instead since further generic type information will
// be erased at runtime
if (list instanceof ArrayList<Integer>) {
	// ...
}

根据提示可以利用list instanceof ArrayList<?>

数组和泛型

Object[] objects = new String[10]; // Ok
List<Object> list = new ArrayList<String>(); // Type mismatch: cannot convert from ArrayList<String> to List<Object>

对于数组右面的声明是数组里包含的内容,可以是Object类或Object的子类
对于泛型右面的声明必须和左边的声明一模一样,除非使用通配符,但是对T赋值的时候,依然可以赋值T的子类,如下:

Box<Object> box = new Box<>();
box.setT("123");

参考

CS-Notes
java 泛型详解
Java泛型详解
10 道 Java 泛型面试题
泛型

猜你喜欢

转载自blog.csdn.net/qq_21687635/article/details/89736026