目录
1、定义
就是允许在定义类、接口时通过一个标识表示类中某个属性的类就是允许在定义类、接口时通过一个标识表示类中某个属性的类。
2、特点
2.1、集合接口或集合类在jdk5时都修改为带泛型的结构
2.2、在实例化的集合类的时候可以指明具体的泛型类型。
例: List<Integer> list = new ArrayList()
2.3、泛型的类型必须时类,不能是基本数据类型。如果要用基本数据类型需转为包装类
2.4、如果实例化时没有指明泛型的类型。默认类型为java.lang.Object类型
2.5、使用泛型能够在编译时而不是运行时检测错误
3、自定义泛型结构
3.1、自定义泛型类、泛型接口
a、静态方法中不能使用泛型
b、异常类不能是泛型的
public class Test<T> {
// T,K,V不代表值,而是代表类型。这里使用任意字母都可以。可以设置多个参数<T,K>
String name;
int age;
T t;
}
public static void main(String[] args) {
Test<String> test = new Test<>();
test.setT("aa");
}
// 如果子类继承带泛型的父类,父类指明了泛型类型时。实例化子类时不需要指明泛型。
public class SubTest extends Test<Integer>{
}
// 子类未指定泛型
public class SubTest1<T> extends Test<T>{
}
public static void main(String[] args) {
SubTest subTest = new SubTest();
subTest.setT(11);
SubTest1<String> subTest1 = new SubTest1<>();
subTest1.setT("bb");
}
3.2、自定义泛型方法
在方法中出现泛型结构,泛型参数与类的泛型参数没有任何关系
public static void main(String[] args) {
Test<String> test = new Test<>();
Integer[] arr = new Integer[]{1,2,3};
// 调用方指明泛型即可,与类Test中的泛型没有任何关系
List<Integer> list = test.getList(arr);
}
public class Test<T> {
// 可以声明静态的。因为泛型参数是在调用方法的时候确定的。并非在实例化时确定的
public static <E> List<E> getList(E[] arr) {
ArrayList<E> arrayList = new ArrayList<>();
for (E e: arr) {
arrayList.add(e);
}
return arrayList;
}
}
// 静态方法中不能使用类的泛型
// public static void show(T test){
// }
4、继承性方面
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口。G<B>并不是G<A>的子类型
例如:String是Object的子类,但List<String> 并不是List<Object>的子类
5、通配符的使用
1、使用通配符类型? 例:List<?>
2、读取List<?>集合中的元素时,永远是安全的。因为不管list的真实类型是什么,它包含的都是Object
3、写入list中的元素时,不行。因为我们不知道元素类型就不能添加。null值除外
public static void main(String[] args) {
List<?> list = null;
list.add(null);
// list.add(11); 编译不通过
List<String> list1 = new ArrayList<>();
list1.add("aa");
listTest(list1);
}
public static void listTest(List<?> list1) {
for (Object o : list1) {
System.out.println(0);
}
}
注意点:
1、不能用在泛型方法上,返回值类型面前<>不能使用?
例:public static<?> void test(ArrayList<?> list) {}
2、不能用在泛型类的声明上
例:class Test<?> {}
3、不能用在创建对象上(new ArrayList<?> )
例:ArrayList<?> list = new ArrayList<?> ();