泛型
在前面学习集合时,我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这是他们都会被提升成Object类型,当我们在取出每一个对象,并且进行相应操作,这时必须采用类型转换。
看下面的代码:
import java.util.ArrayList; import java.util.Iterator; public class Demo01Generic { public static void main(String[] args) { /* 创建集合对象,不使用泛型 好处:集合不使用泛型,默认的就是Object类型,可以存储任意类型的数据 弊端:不安全,会发生异常 */ ArrayList list = new ArrayList(); list.add(1); list.add("aaa"); Iterator it = list.iterator(); while(it.hasNext()){ Object obj = it.next(); System.out.println(obj); /* 如果需要使用length()方法来返回字符串长度 由于父类不能直接使用子类方法 需要使用向下转型 */ String s = (String) obj; /* 注意: 编译器可能会报错 因为不是所有的数据都是String类型 */ } } }
import java.util.ArrayList; import java.util.Iterator; public class Demo01Generic { public static void main(String[] args) { /* 创建集合对象,使用泛型 好处: 1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型 2.把运行期异常(代码运行之后会抛出异常),提升到了编译期(写代码的时候回报错) 弊端:只能存储一种类型的数据 */ ArrayList<String> list = new ArrayList(); list.add(1);//报错 list.add("aaa"); list.add("bbb"); list.add("ccc"); Iterator<String> it = list.iterator(); while(it.hasNext()){ Object obj = it.next(); System.out.println(obj); } } }
泛型的定义与使用
当我们不确定要使用什么数据类型时,我们可以使用泛型。
泛型可以接受任意数据类型,Integer, String, Student...
public class GenericClass<E> { private E variate; public E getVariate() { return variate; } public void setVariate(E variate) { this.variate = variate; } } public class DemoMain { public static void main(String[] args) { //不使用泛型,默认为Object类型 GenericClass gc = new GenericClass(); gc.setVariate("不使用泛型,默认为Object类型"); Object obj = gc.getVariate(); //创建GenericClass对象,泛型使用Integer类型 GenericClass<Integer> gc2 = new GenericClass<>(); gc2.setVariate(10); Integer integer = gc2.getVariate(); //创建GenericClass对象,泛型使用String类型 GenericClass<String> gc3= new GenericClass<>(); gc3.setVariate("String类型"); String string = gc3.getVariate(); } }
定义和使用含有泛型的方法
格式:
修饰符 < 泛型 > 返回值类型 方法名称 (参数列表(使用泛型)){
方法体
}
含有泛型的方法,在调用方法的时候确定泛型的数据类型
传递什么类型的参数,泛型就是什么类型
public class Demo02Main { public static void main(String[] args) { GenericMethod gm = new GenericMethod(); gm.method01("abc"); gm.method01(2.5); gm.method01(2); System.out.println("==========="); //调用静态方法 GenericMethod.method02("abc"); GenericMethod.method02(2.5); GenericMethod.method02(2); } }
定义和使用含有泛型的接口
有两种定义泛型接口的方法:
1.定义接口的实现类,实现接口,指定接口的泛型
2.接口和类使用同一种泛型
public class Demo03Main { public static void main(String[] args) { //创建GenericInterfaceImpl对象 GenericInterfaceImpl gi = new GenericInterfaceImpl(); gi.method("String类型"); //创建GenericInterfaceImpl对象 GenericInterfaceImpl2<String> gi2 = new GenericInterfaceImpl2<>(); gi2.method("abc"); GenericInterfaceImpl2<Integer> gi3 = new GenericInterfaceImpl2<>(); gi3.method(3); GenericInterfaceImpl2<Double> gi4 = new GenericInterfaceImpl2<>(); gi4.method(8.8); } }
泛型通配符
当使用泛型类或者接口是,传递数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能用Object类中的共性方法,集合中元素自身方法无法使用。
不知道使用什么类型来接受的时候,此时可以使用?,表示未知通配符。
此时只能接受数据,不能往该集合中存储数据。
使用方式:不能创建对象使用,只能作为方法的参数使用
import java.util.ArrayList; import java.util.Iterator; public class Demo04Generic { public static void main(String[] args) { ArrayList<Integer> arr1 = new ArrayList<>(); arr1.add(1); arr1.add(2); arr1.add(3); ArrayList<String> arr2 = new ArrayList<>(); arr2.add("aaa"); arr2.add("bbb"); arr2.add("ccc"); printArray(arr1); printArray(arr2); } public static void printArray(ArrayList<?> list){ Iterator<?> it = list.iterator(); while(it.hasNext()){ Object obj = it.next(); System.out.println(obj); } } }
泛型的上限限定
? extends E : 代表使用的泛型只能是E类型的子类和本身
泛型的下限限定
? super E : 代表使用的泛型只能是E类型的父类和本身