1.Java提供的泛型支持
增加了泛型支持后的集合,完全可以记住集合中元素的类型,并可以在编译时检查集合中元素的类型,如果试图向集合中添加不满足类型要求的对象,编译器就会提示错误。
创建的方法是:在集合接口、类后增加尖括号,尖括号里放一个数据类型,如:
List<String> str = new ArrayList<>(); //对于后面的<>,系统会自动识别为String类型
2.定义泛型接口、类
(1)如:
public class Apple<T> //定义Apple类时使用了泛型声明
Apple<String> a1 = new Apple<>(“苹果”); //传入参数
但构造器仍是Apple(),不是Apple<T>()
(2)泛型类派生子类
当使用这些接口、父类时不能再包含泛型形参,即上面的T要具体为String,如:
public class A extends Apple<String>{…}
(3)不存在泛型类
如Array<String>相对于Array只是说明只能添加String对象作为集合元素,不是新类。
在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用泛型形参。
3.类型通配符
(1)若集合形参的元素类型不确定,则使用类型通配符<?>,它的元素类型可以匹配任何类型。注意,List<String>类不是List<Object>的子类。
(2)类型通配符上限
指定类型通配符的上限,只能从集合中取元素,不能向集合中添加元素。(因为编译器没法确定集合元素实际是哪种类型)
比如Foo是Bar的子类,这样A<Bar>就相当于A<? entends Foo>的子类,可以将A<Bar>赋值给A<? entends Foo>类型的变量,这种型变称为协变。(协变只出不进)
(3)类型通配符下限
比如Foo是Bar的子类,当程序需要一个A<? super Bar>变量时,程序可以将A<Foo>、A<Object>赋值给A<? super Bar>类型的变量,这种型变称为逆变。
(4)设定泛型形参的上限
若需要为泛型形参设定多个上限并实现多个接口,要求类上限须为第一位,如:
public class Apple<T entends Number & java.io.Serializable>{…}
4.泛型方法
格式如下:修饰符 <T , S> 返回值类型 方法名(形参列表){方法体}
如:
static <T> void fromArrayToCollection(T[] a , Collection<T> c)
{
…
}
泛型方法与类型通配符之间的转换,如:
同时使用泛型方法和通配符的情况:
public class Collection{
public static <T> void copy(List<T> dest,List<? extends T> src)
{…}
}
改为使用泛型方法,不使用类型通配符:
class Collection{
public static <T , S entends T> void copy (List<T> dest , List<S> src)
{…}
}
5.菱形用法(Java7新增菱形语法)
允许调用构造器时在构造器之后使用一对尖括号来代表泛型信息。如:
class MyClass<E>
{
public <T> MyClass(T t){…}
}
6.擦除
定义一个List<Integer>对象,这个List<Integer>对象保留了集合元素的类型信息,当把这个List<Integer>对象赋给一个List类型的list后,编译器就会丢失前者的泛型信息,即丢失list集合里元素的类型信息,这就是典型的擦除。
7.Java不支持创建泛型数组
如下面代码是不允许的:
List<String>[] arr = new ArrayList<String> [10];
//只能声明,如new ArrayList<String>[]