什么是泛型
泛型指的是java的参数化类型,是为了让集合可以记住元素的数据类型,不加泛型的集合里的元素类型都是Object类型,一旦里面有不同的对象进行强转时就会发生异常,如将Integer强转为String
给集合添加类型就为泛型,如
ArrayList < String> arrayList = new ArrayList < String>();
java7简化了定义方式,菱形语法,后面尖括号不需在写类型
ArrayList < String> arrayList = new ArrayList < >();
深入泛型
泛型不止可以在集合上使用,也可以在定义接口、类、方法时使用类型形参
定义泛型接口、类
我给scanner类添加了一个s类型形参,构造器就可以调用这个形参作为参数,在构造器定义时不需要输入尖括号,但是在调用时需要尖括号并且在调用构造器时应该为该类型形参传入实际的参数类型。
这样做的好处是可以给一个构造器的不同对象传入不同的值
public class scanner<s>
{
private s ss;
public scanner(s ss)
{
this.ss=ss;
}
public static void main(String[] args) {
scanner<String> scanner = new scanner<>("2");
scanner<Integer> scanner2 = new scanner<>(2);
scanner<s> sscanner3 = new scanner<>();----错误写法
}
}
从泛型类派生子类
当创建了带泛型声明的接口、父类后,可以为该接口创建实现类,但是当使用这些接口、父类时不能再包含类型参数,在使用类、接口、方法时应该为类型形参传入实际的类型
public class Apple{}
public class A extends Apple < T>{}-----错误写法
public class A extends Apple < String>{}-----正确写法
如果public class A extends Apple < String>{}实现了 Apple < T>{},则在Apple 类中所有使用到Y类型形参的地方都会被替换成String类型
在静态方法、静态初始化块或静态变量的声明和初始化中不允许使用类型形参
类型通配符
泛型通配符? 代表任意泛型
既然?代表任意泛型,那么换句话说,这个容器什么泛型都有可能,所以只能以Object的形式取出来并且不能往里面放对象,因为不知道到底是一个什么泛型的容器
ArrayList heroList<? extends Hero> 表示这是一个Hero泛型或者其子类泛型
heroList 的泛型可能是Hero
heroList 的泛型可能是APHero
heroList 的泛型可能是ADHero
所以 可以确凿的是,从heroList取出来的对象,一定是可以转型成Hero的,但是,不能往里面放东西,因为
放APHero就不满足
放ADHero又不满足
ArrayList heroList<? super Hero> 表示这是一个Hero泛型或者其父类泛型
heroList的泛型可能是Hero
heroList的泛型可能是Object
可以往里面插入Hero以及Hero的子类
但是取出来有风险,因为不确定取出来是Hero还是Object
如果希望只取出,不插入,就使用? extends Hero
如果希望只插入,不取出,就使用? super Hero
如果希望,又能插入,又能取出,就不要用通配符?
定义泛型方法
因为集合 Collection< String>不是Collection< Object>的子类型,所以arrsList 是不能添加到Collection< Object> c中,这时候就可以使用泛型方法来解决这个问题
public static void insterts(Object[] a, Collection<Object> c)
{
}
public static void main(String[] args) {
String[] arrs ={"a","b"};
List<String>arrsList = new ArrayList<>();
insterts(arrs,arrsList);-----报错
}
定义泛型方法在修饰符和返回值类型之间添加尖括号,用泛型来代替固定的数据类型
public static <T> void insterts(Object[] a, Collection<T> c)
{
}
public static void main(String[] args) {
String[] arrs ={"a","b"};
List<String>arrsList = new ArrayList<>();
insterts(arrs,arrsList);------不报错
List<Integer>arrsList2 = new ArrayList<>();
insterts(arrs,arrsList2);------不报错
}
如果你给系统造成了迷惑,你就出错了,这两个集合的类型形参都是T,但是下面的集合类型一个是String,一个是Integer,这样就导致T不知道应该选哪个作为实际参数
public static <T> void insterts(Collection<T> b, Collection<T> c)
{
}
public static void main(String[] args) {
List<String>arrsList = new ArrayList<>();
List<Object>arrsList2 = new ArrayList<>();
insterts(arrsList,arrsList2);-------报错
}
修改办法:
只要insterts方法的前一个Collection集合中的元素类型是后一个Collection集合元素类型的子类即可
public static <T> void insterts(Collection<? extends T> b, Collection<T> c)
{
}
public static void main(String[] args) {
List<String>arrsList = new ArrayList<>();
List<Object>arrsList2 = new ArrayList<>();
insterts(arrsList,arrsList2);
}