唧唧复唧唧
——木兰诗
冗长的代码实在无趣,这就是为什么程序员会连自己写的代码都不愿意去看.看了就头痛,代码整洁才是关键.
一、什么是泛型?为什么要使用泛型?
且看代码:
1 public class GenericsDemo { 2 3 public static void main(String[] args) { 4 List list = new ArrayList<>(); 5 list.add("1"); 6 list.add("2"); 7 list.add("3"); 8 list.add(5);//不小心把Integer丢进了集合中 9 //编译不报错,运行时发生java.lang.ClassCastException异常 10 list.forEach(str -> System.out.println((String)str)); 11 } 12 }
第8行代码不小心把Integer丢了进去,会引发ClassCastException
使用了泛型后:
1 public class GenericsDemo { 2 3 public static void main(String[] args) { 4 5 List<String> list = new ArrayList<>(); 6 list.add("1"); 7 list.add("2"); 8 list.add(3);//不小心把Integer丢进了集合中,编译报错 9 } 10 }
第一段代码可能引发运行时异常ClassCastException的代码,在上面代码中直接编译报错了。
1 public class GenericsDemo { 2 3 public static void main(String[] args) { 4 5 List<String> list = new ArrayList<>(); 6 list.add("1"); 7 list.add("2"); 8 list.add("3"); 9 list.add("4"); 10 list.forEach(str -> System.out.print(str)); 11 } 12 }
发现了么,第10行不用吧str强制转换为String类型了。
1 public class GenericsDemo { 2 3 public static void main(String[] args) { 4 Object o = new Integer(10); 5 Float f = (Float)o; 6 } 7 }
程序在编译时并不知道你到底传了什么类型的变量。由于多态(想想猫和狗的例子),程序运行的的时候可能发生类型转换异常。
为了避免ClassCastException运行时异常,Java引入泛型机制。
使用泛型的好处:
1、避免了ClassCastException
2、免去了大量的强制转换
二、定义泛型类和泛型接口
上代码:
使用泛型定义类(泛型定义接口的道理是一样的)
1 public class Bag <T>{ 2 3 private T content; 4 5 Bag(T content) { 6 this.content = content; 7 } 8 9 T getContent() { 10 return content; 11 } 12 13 void setContent(T content) { 14 this.content = content; 15 } 16 }
这里想下普通的定义方法,T是特定的类型(比如String)。这里的T可以是任意类型,类型范围很广。
1 public class TestBag { 2 3 public static void main(String[] args) { 4 Bag<String> bag = new Bag<String>("book"); 5 Integer cintent = bag.getContent();//编译出错 6 String content1 = bag.getContent(); 7 } 8 }
三、使用extends关键字限定类型参数
上代码:
1 public class LimitBag <T extends Number>{ 2 3 private T content; 4 5 LimitBag(T content) { 6 this.content = content; 7 } 8 9 T getContent() { 10 return content; 11 } 12 13 void setContent(T content) { 14 this.content = content; 15 } 16 }
1 public class TestBag { 2 3 public static void main(String[] args) { 4 5 LimitBag<String> bag = new LimitBag<String>("book");//编译出错 6 LimitBag<Integer> bag2 = new LimitBag<Integer>(1);//合法 7 } 8 }
四、定义泛型数组
上代码:
1 public class GenericArray<T> { 2 3 private T[] content; 4 5 GenericArray(T[] content) { 6 this.content = content; 7 } 8 9 T[] getContent() { 10 return content; 11 } 12 13 void setContent(T[] content) { 14 this.content = content; 15 } 16 17 }
1 public class TestBag { 2 3 public static void main(String[] args) { 4 5 String[] content = {"1","2","3"}; 6 GenericArray<String> ss= new GenericArray<>(content); 7 for (String item : ss.getContent()) { 8 System.out.println(item); 9 } 10 } 11 }
五、定义泛型方法
上代码:
1 public class MethodTest { 2 3 public static <E> void printArray(E[] arr){ 4 for (E item : arr) { 5 System.out.println(item); 6 } 7 } 8 public static <T extends Comparable<T>> T max(T x,T y){ 9 return x.compareTo(y)>0?x:y; 10 } 11 public static void main(String[] args) { 12 Integer[] arr = {1,2,3};//必须是包装类 13 printArray(arr); 14 System.out.println(max("B", "a")); 15 } 16 17 }
六、问号通配符
上代码
1 public class WildCast { 2 3 public static void main(String[] args) { 4 Set<String> set = new HashSet<String>();//向上转型 5 //HashSet<Object> set = new HashSet<String>();//编译出错Type mismatch,泛型Object和泛型String之间不存在继承关系 6 } 7 }
在看下面代码:
1 public class WildCast { 2 3 public static void main(String[] args) { 4 5 List<Integer> list = new ArrayList<>(); 6 list.add(11); 7 print(list);//编译出错 8 printNew(list); 9 } 10 11 private static void printNew(Collection<?> collection) { 12 // TODO Auto-generated method stub 13 collection.forEach(obj -> System.out.println(obj)); 14 } 15 16 private static void print(Collection<Object> collection) { 17 // TODO Auto-generated method stub 18 collection.forEach(obj -> System.out.println(obj)); 19 } 20 }
泛型<Integer>和泛型<Object>没有继承关系,不能传递。所以使用通配符<?>