2019独角兽企业重金招聘Python工程师标准>>>
泛型,即“参数化类型”
(1)泛型只在编译阶段有效;
0、边界符:<T extends Comparable<T>>,说明T 必须继承Comparable才能使用
(1)T可以为任意标识,如T、E、K、V等常用于表示泛型;
(2)泛型的上下边界添加,必须与泛型的声明在一起;
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;
}
1、泛型类
(2)泛型类型:逻辑上是多个不同的类型,实际上是相同基本类型;
(3)泛型类型参数只能是类类型,不能是简单类型;
2、泛型方法
(1)泛型类,是在实例化类的时候指明泛型的具体类型;
(2)泛型方法,是在调用方法的时候指明泛型的具体类型;
(4)多个泛型类型例子:
class GenerateTest<T>{ //<T>在类中声明T泛型,与下文的方法声明的T不是同一个
public <T,H,K> K showKeyName(Generic<T> container){
//出现多个泛型类型时使用,T、K可以在任意地方使用
//方法内的T不是 外面类的T
}
}
(3)public 与 返回值中间<K,V>可以理解为声明此方法为泛型方法;
1、虽然Integer和Double是Number的子类,但是Box<Integer>
或者Box<Double>
与Box<Number>
之间无关;
2、通配符?: List<? extends T> list
(1)实现了<? extends T>
的集合类,对外提供get方法,不可以set;
(2)实现了<? super T>
的集合类,可以使用set,不能get;
(3)同时读取、写入,不能使用通配符,或者<? extends T>
和<? super T>
同时使用;
(4)?是类型实参,而不是类型形参;
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i=0; i<src.size(); i++)
dest.set(i, src.get(i));
}
}
3、类型擦除
(1)java泛型只能用于编译器静态类型检查,编译后代码会擦除类型信息;
(2)运行期jvm不知道泛型所指具体类型:Node<String>
或Node<Integer>
,均视为Node<Object>
编译前:
编译后:
public class Node {
private Object data;
private Node next;
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
public Object getData() { return data; }
// ...
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
编译前:
编译后:
public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
public Comparable getData() { return data; }
// ...
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
4、问题:不允许创建泛型数组,除非使用通配符
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error
List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li; // Correct.
Integer i = (Integer) lsa[1].get(0); // OK
public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2); // true 泛型擦除的缘故
}
}
5、问题:编译器会偷偷帮我们实现Bridge method:
编译前:
编译后:
class MyNode extends Node {
// Bridge method generated by the compiler
public void setData(Object data) {/编译器自动生成
setData((Integer) data);
}
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
// ...
}
6、问题:参数类型创建实例,编译不通过:
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
反射可以创建实例:
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}
public static void main(String[] args) {
List<String> ls = new ArrayList<>(); //调用方法
append(ls, String.class);
}
7、问题:无法对泛型直接使用instanceof:
public static <E> void rtti(List<E> list) {
if (list instanceof ArrayList<Integer>) { // compile-time error
// ...
}
}
通配符可以解决:
public static void rtti(List<?> list) {
if (list instanceof ArrayList<?>) { // OK; instanceof requires a reifiable type
// ...
}
}
8、可变参数:
9、静态方法:
(1)静态方法无法访问类上定义的泛型;
(2)如果要使用,必须将泛型定义在方法上;