1、泛型的引入
集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换。比如下面程序:
1 public class GenericDemo { 2 public static void main(String[] args) { 3 List list = new ArrayList(); 4 list.add("abc"); 5 list.add("love"); 6 list.add(5);//由于集合没有做任何限定,任何类型都可以给其中存放 7 //相当于:Object obj=new Integer(5); 8 9 Iterator it = list.iterator(); 10 while(it.hasNext()){ 11 //需要打印每个字符串的长度,就要把迭代出来的对象转成String类型 12 String str = (String) it.next();//String str=(String)obj; 13 //编译时期仅检查语法错误,String是Object的儿子可以向下转型 14 //运行时期String str=(String)(new Integer(5)) 15 //String与Integer没有父子关系所以转换失败 16 //程序在运行时发生了问题java.lang.ClassCastException 17 System.out.println(str.length()); 18 } 19 } 20 }
2、泛型的定义和使用
1 /* 2 * JDK1.5 出现新的安全机制,保证程序的安全性 3 * 泛型: 指明了集合中存储数据的类型 <数据类型> 4 */ 5 6 public class GenericDemo { 7 public static void main(String[] args) { 8 function(); 9 } 10 11 public static void function(){ 12 Collection<String> coll = new ArrayList<String>(); 13 coll.add("abc"); 14 coll.add("rtyg"); 15 coll.add("43rt5yhju"); 16 // coll.add(1); 17 18 Iterator<String> it = coll.iterator(); 19 while(it.hasNext()){ 20 String s = it.next(); 21 System.out.println(s.length()); 22 } 23 } 24 }
3、Java中的伪泛型
泛型只在编译时存在,编译后就被擦除,在编译之前我们就可以限制集合的类型,起到作用。例如:
ArrayList<String> al=new ArrayList<String>();
编译后:
ArrayList al=new ArrayList();
4、泛型类
(1)定义格式
修饰符 class 类名<代表泛型的变量> { } 例如,API中的ArrayList集合: class ArrayList<E>{ public boolean add(E e){ } public E get(int index){ } }
(2)使用格式
创建对象时,确定泛型的类型 例如,ArrayList<String> list = new ArrayList<String>(); 此时,变量E的值就是String类型 class ArrayList<String>{ public boolean add(String e){ } public String get(int index){ } } 例如,ArrayList<Integer> list = new ArrayList<Integer>(); 此时,变量E的值就是Integer类型 class ArrayList<Integer>{ public boolean add(Integer e){ } public Integer get(int index){ } }
5、泛型的方法
(1)定义格式
修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
(2)泛型方法的使用
例如,API中的ArrayList集合中的方法: public <T> T[] toArray(T[] a){ } //该方法,用来把集合元素存储到指定数据类型的数组中,返回已存储集合元素的数组 使用格式:调用方法时,确定泛型的类型 例如: ArrayList<String> list = new ArrayList<String>(); String[] arr = new String[100]; String[] result = list.toArray(arr); 此时,变量T的值就是String类型。变量T,可以与定义集合的泛型不同 public <String> String[] toArray(String[] a){ } 例如: ArrayList<String> list = new ArrayList<String>(); Integer[] arr = new Integer[100]; Integer [] result = list.toArray(arr); 此时,变量T的值就是Integer类型。变量T,可以与定义集合的泛型不同 public <Integer> Integer[] toArray(Integer[] a){ }
6、泛型的接口
1 /* 2 * 带有泛型的接口 3 * 4 * public interface List <E>{ 5 * abstract boolean add(E e); 6 * } 7 * 8 * 实现类,先实现接口,不理会泛型 9 * public class ArrayList<E> implements List<E>{ 10 * } 11 * 调用者 : new ArrayList<String>() 后期创建集合对象的时候,指定数据类型 12 * 13 * 14 * 实现类,实现接口的同时,也指定了数据类型 15 * public class XXX implements List<String>{ 16 * } 17 * new XXX() 18 */ 19 public class GenericDemo2 { 20 21 }
7、泛型的好处
(1)将运行时期的ClassCastException,转移到了编译时期变成了编译失败;
(2)避免了类型强转的麻烦。
1 public class GenericDemo { 2 public static void main(String[] args) { 3 List<String> list = new ArrayList<String>(); 4 list.add("abc"); 5 list.add("love"); 6 //list.add(5);//当集合明确类型后,存放类型不一致就会编译报错 7 //集合已经明确具体存放的元素类型,那么在使用迭代器的时候,迭代器也同样会知道具体遍历元素类型 8 9 Iterator<String> it = list.iterator(); 10 while(it.hasNext()){ 11 String str = it.next(); 12 System.out.println(str.length()); //当使用Iterator<String> 13 //控制元素类型后,就不需要强转了。获取到的元素直接就是String类型 14 } 15 } 16 }
8、泛型的通配符
1 /* 2 * 泛型的通配符 3 */ 4 public class GenericDemo { 5 public static void main(String[] args) { 6 ArrayList<String> array = new ArrayList<String>(); 7 8 HashSet<Integer> set = new HashSet<Integer>(); 9 10 array.add("123"); 11 array.add("456"); 12 13 set.add(789); 14 set.add(890); 15 16 iterator(array); 17 iterator(set); 18 } 19 /* 20 * 定义方法,可以同时迭代2个集合 21 * 参数: 怎么实现 , 不能写ArrayList,也不能写HashSet 22 * 参数: 或者共同实现的接口 23 * 泛型的通配,匹配所有的数据类型 ? 24 */ 25 public static void iterator(Collection<?> coll){ 26 Iterator<?> it = coll.iterator(); 27 while(it.hasNext()){ 28 //it.next()获取的对象,什么类型 29 System.out.println(it.next()); 30 } 31 } 32 }
9、泛型的限定
1 /* 2 * 将的酒店员工,厨师,服务员,经理,分别存储到3个集合中 3 * 定义方法,可以同时遍历3集合,遍历三个集合的同时,可以调用工作方法 4 */ 5 import java.util.ArrayList; 6 import java.util.Iterator; 7 public class GenericTest { 8 public static void main(String[] args) { 9 //创建3个集合对象 10 ArrayList<ChuShi> cs = new ArrayList<ChuShi>(); 11 ArrayList<FuWuYuan> fwy = new ArrayList<FuWuYuan>(); 12 ArrayList<JingLi> jl = new ArrayList<JingLi>(); 13 14 //每个集合存储自己的元素 15 cs.add(new ChuShi("张三", "后厨001")); 16 cs.add(new ChuShi("李四", "后厨002")); 17 18 fwy.add(new FuWuYuan("翠花", "服务部001")); 19 fwy.add(new FuWuYuan("酸菜", "服务部002")); 20 21 jl.add(new JingLi("小名", "董事会001", 123456789.32)); 22 jl.add(new JingLi("小强", "董事会002", 123456789.33)); 23 24 // ArrayList<String> arrayString = new ArrayList<String>(); 25 iterator(jl); 26 iterator(fwy); 27 iterator(cs); 28 29 } 30 /* 31 * 定义方法,可以同时遍历3集合,遍历三个集合的同时,可以调用工作方法 work 32 * ? 通配符,迭代器it.next()方法取出来的是Object类型,怎么调用work方法 33 * 强制转换: it.next()=Object o ==> Employee 34 * 方法参数: 控制,可以传递Employee对象,也可以传递Employee的子类的对象 35 * 泛型的限定 本案例,父类固定Employee,但是子类可以无限? 36 * ? extends Employee 限制的是父类, 上限限定, 可以传递Employee,传递他的子类对象 37 * ? super Employee 限制的是子类, 下限限定, 可以传递Employee,传递他的父类对象 38 */ 39 public static void iterator(ArrayList<? extends Employee> array){ 40 41 Iterator<? extends Employee> it = array.iterator(); 42 while(it.hasNext()){ 43 //获取出的next() 数据类型,是什么Employee 44 Employee e = it.next(); 45 e.work(); 46 } 47 } 48 }