泛型,即类型形参,就是把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型,把类型当作是参数一样传递,而泛型所指的类型只能是引用类型不能是基本类型。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("字符串"); arrayList.add(1); }
当没有使用泛型时,可以向一个集合里插入各种类型的数据,当需要取出数据时就得需要知道每个数据的类型,增加了编程的复杂度。
使用泛型后,只允许集合里存储Integer类型的数据,向集合里存储其它类型的数据会报错。
泛型的使用
泛型类:public class Test<T>}{ }
泛型接口:public interface Test<T>{ }
泛型方法:public <T> void Test(T name){ }
定义一个泛型接口,泛型形参E也可作为类型使用
public interface Test<T> { T getName(T name); }
当一个类实现这个接口时,如果接口不带泛型,默认为Object类型,如果接口带着泛型,类名也要加上泛型。
public class Student implements Test{ @Override public Object getName(Object name) { return null; } }
public class Student<T> implements Test<T>{ @Override public T getName(T name) { return null; } }
定义一个泛型类:
public class Person <T>{ private T name; T getName(T name){ this.name =name; return this.name; } public Person(T name){ this.name =name; } }
带泛型的类定义构造器时,构造器不必带泛型。
当实例化一个泛型时,无论是Person<String> person = new Person<>("zzz");
还是Person<Integer> person1 = new Person<>(123),不管为泛型传入哪一种类型实参,它们都被看作一个类,在内存中也只占用一块内存空间。所以在静态方法,静态初始化块,静态变量中不允许使用泛型形参。
类型通配符
定义一个getArrayList方法返回一个ArrayList集合,ArrayList<?>表示可以是任何类型的ArrayList集合,?就被称为通配符,它就代表各种元素类型。
public static void main(String[] args) { ArrayList<Integer> arrayList1 = new ArrayList<>(); arrayList1.add(1); ArrayList<String> arrayList2 = new ArrayList<>(); arrayList2.add("aaa"); ArrayList ar1 = getArrayList(arrayList1); ArrayList ar2 = getArrayList(arrayList2); } public static ArrayList getArrayList(ArrayList<?> arrayList){ return arrayList; }
设置类型通配符的上限:?extends E ,表示可以接收E以及E的子类型的泛型,这里面的E不止是类,也可以是接口。
定义一个方法,返回一个存放Person类及它的子类型的ArrayList集合:
public static ArrayList getArrayList(ArrayList<?extends Person> arrayList){ return arrayList; }
arrayList1存放的是Person类的子类Student,可以被方法返回,Cat类不是Person类的子类,调用getArrayList方法会出错。
通配符的下限:? super E, 表示传入的类型必须得是E以及E的父类。
Person是Student类的子类。