泛型
在学习集合的时候,集合可以存放任意对象,只要把对象存储到集合后,他们都会被提升到Object类型,在我们取出每一个对象,并进行相应操作时,就必须采用类型转换。而在转换的时候就容易产生类型转换异常。为了解决这个问题,就使用了泛型。
泛型定义与使用
让一个集合只存储同一数据类型
1.定义泛型类
(1) 定义格式:
修饰符 class 类名<代表泛型的变量> { }
//API中ArrayList集合
class ArrayList<E>{
public boolean add(E e){ }
public E get(int index){ }
....
}
(2) 什么时候确定泛型
在创建对象的时候确定泛型
ArrayList<String> list = new ArrayList<String>();
这时候API中的ArrayList就可以理解为
class ArrayList<String>{
public boolean add(String e){ }
public String get(int index){ }
...
}
总之,就是我们在创建对象的时候传入什么类型,我们的类就是什么类型。
2.定义泛型方法
(1) 定义格式:
修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
public class Test {
public <E> void show(E e) {
System.out.println(e.getClass());
}
public <E> E show1(E e) {
return e;
}
}
(2) 什么时候确定泛型
在方法调用时,确定泛型的类型
public static void main(String[] args) {
// 创建对象
Test t = new Test();
t.show("raaa");//class java.lang.String
t.show(123);//class java.lang.Integer
String t1=t.show1("bbb");//bbb
}
(3) 泛型方法的泛型可以和泛型类中的泛型通用吗?
public class Test<E> {
public void show(E e) {
System.out.println(e.getClass());
}
public <E> E show1(E e) {
return e;
}
}
泛型方法的泛型可以使用泛型类的泛型,也可以不使用,不使用的话就把E换成别的字母就可以了,而且不会影响泛型方法确定泛型的时机
(4) 静态方法可以使用当前类的泛型吗?
public class Test<E> {
public static <E> void show(E e) {
System.out.println(e.getClass());
}
//普通静态方法不能使用当前类的泛型
public static void show(E e) {
System.out.println(e.getClass());
}
}
静态方法中可以使用当前类的泛型,前提条件是当前类必须是泛型方法,因为他确定泛型的时机与类没有关系,只和方法调用的时候有关系。如果是普通静态方法则不能使用当前类的泛型,因为这个时候对象还没有创建出来
3.含有泛型的接口
(1) 定义格式:
修饰符 interface接口名<代表泛型的变量> { }
(2) 什么时候确定泛型
public interface TestInterface<E>{
public abstract void add(E e);
public abstract E getE();
}
①确定类时确定泛型的类型
public class Imp1 implements TestInterface<String> {
@Override
//此时泛型的类型就是String类型
public void add(String e) {
// 省略...
}
@Override
public String getE() {
return null;
}
}
②确定类时不确定泛型的类型,直到创建对象的时候确定泛型。这时要求当前的类必须是一个泛型类,因为当泛型类在被创建的时候,间接的确定了接口中的泛型。
public class Imp1<E> implements TestInterface<E> {
@Override
public void test(E e) {
System.out.println(e.getClass());
}
@Override
public E getE() {
return null;
}
}
4.泛型通配符
1.当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身的方法无法使用。
2.通配符的基本使用:
①不知道使用什么类型来接收数据的时候,此时可以使用?,?表示未知通配符此时只能接受数据,不能往该集合中存储数据。
public static void main(String[] args) {
Collection<Intger> list1 = new ArrayList<Integer>();
Test(list1);
Collection<String> list2 = new ArrayList<String>();
Test(list2);
}
//定义一个方法用于接受任意单列集合的任何数据类型作为参数传递
public static void Test(Collection<?> c){}
②通配符高级使用-----受限泛型
之前设置泛型的时候,实际上是可以任意设置的,Java的泛型中还可以指定一个泛型的上限和下限
泛型的上限:
格式:类型名称 <? extends 类 > 对象名称
意义:只能接受该类型及其子类
泛型的下限:
格式:类型名称 <? super 类 > 对象名称
意义:只能接受该类型及其父类
例如:已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
public static void main(String[] args) {
Collection<Intger> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
test1(list1);
test1(list2);//报错
test1(list3);
test1(list4);//报错
test2(list1);//报错
test2(list2);//报错
test2(list3);
test2(list4);
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void test1(Collection<? extends Number> c){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void test2(Collection<? super Number> c){}