泛型:
泛型是JDK1.5中一个最重要的特性,通过引入泛型,我们将获得编译时类型的安全,和运行时更小的抛出ClassCastexceptions的可能.在JDK1.5中,你可以声明一个集合接收或者返回的对象的类型.
泛型之前:
类别定义时的逻辑完全一样,只是里面成员变量的类型不同.
如果需要多个相似的类,需要定义多个文件,不同的只是变量的类别,而逻辑是完全一样的.
IntergerFoo.java
1 public class IntegerFoo{ 2 private Integer foo; 3 4 public Integer getFoo(){ 5 return foo; 6 } 7 8 public void setFoo(Integer foo){ 9 this.foo = foo; 10 } 11 }
BooleanFoo.java
1 public class BooleanFoo{ 2 private Boolean foo; 3 4 public Boolean getFoo() { 5 return foo; 6 } 7 8 public void setFoo(Boolean foo){ 9 this.foo = foo; 10 } 11 }
如果有很多类型的话想用一个类型来替代以上等的类型怎么办,只能用Object类.
ObjectFoo.java
1 public class ObjectFoo{ 2 private Object foo; 3 4 public Object getFoo(){ 5 return foo; 6 } 7 8 public void setFoo(Object foo){ 9 this.foo = foo; 10 } 11 12 public static void main(String[] args){ 13 ObjectFoo foo1 = new ObjectFoo(); 14 ObjectFoo foo2 = new ObjectFoo(); 15 16 foo1.setFoo(new Boolean(false)); 17 Boolean b = (Boolean)foo1.getFoo(); 18 19 foo2.setFoo(new Integer(10)); 20 Integer i = (Integer)foo2.getFoo(); 21 22 ObjectFoo foo3 = new ObjectFoo(); 23 foo3.setFoo(new Boolean(false)); 24 25 String str = (String)foo3.getFoo(); 26 //这个时候编译不会报错,但是运行的时候Object不能转换成String类型的,一定会出错 27 //java.lang.ClassCastException: java.lang.Boolean cannot be caast to java.lang.String 28 } 29 }
定义泛型类别:
如果使用泛型,只要代码在编译时没有出现警告,就不会遇到运行时ClassCastException
所谓泛型就是变量的类型参数化(不是变量本身,是变量的类型).
GenericFoo.java
1 public class GenericFoo<T>{ 2 private T foo; 3 4 public T getFoo(){ 5 return foo; 6 } 7 8 public void setFoo(T foo){ 9 this.foo = foo; 10 } 11 12 public static void main(String[] args){ 13 GenericFoo<Boolean> foo1 = new GenericFoo<Boolean>(); 14 GenericFoo<Integer> foo2 = new GenericFoo<Integer>(); 15 16 foo1.setFoo(new Boolean(false)); 17 foo2.setFoo(new Integer(3)); 18 19 Boolean b = foo1.getFoo(); 20 Integer i = foo2.getFoo(); 21 22 System.out.println(b);//打印输出:false 23 System.out.println(i);//打印输出:3 24 25 //foo1 = foo2; 26 //报错Type mismatch: cannot convert from GenericFoo<Integer> to GenericFoo<Boolean> 27 28 GenericFoo a = new GenericFoo(); 29 a.setFoo("hello"); 30 31 String str = (String)a.getFoo(); 32 System.out.println(str);//输出:hello 33 } 34 }
Generic.java
1 public class Generic<T1, T2>{ 2 private T1 foo1; 3 4 private T2 foo2; 5 6 public T1 getFoo1(){ 7 return foo1; 8 } 9 10 public void setFoo1(T1 foo1){ 11 this.foo1 = foo1; 12 } 13 14 public T2 getFoo2(){ 15 return foo2; 16 } 17 18 public void setFoo2(T2 foo2){ 19 this.foo2 = foo2; 20 } 21 22 public static void main(String[] args){ 23 Generic<Integer, Boolean> foo = new Generic<Integer, Boolean>(); 24 25 foo.setFoo1(new Integer(-20)); 26 foo.setFoo2(new Boolean(false)); 27 28 System.out.println(foo.getFoo1()); 29 System.out.println(foo.getFoo2()); 30 } 31 }
打印输出:
-20
false
Generic2.java
1 public class Generic2<T>{ 2 private T[] fooArray; 3 //泛型数组 4 5 public T[] getFooArray(){ 6 return fooArray; 7 } 8 9 public void setFooArray(T[] fooArray){ 10 this.fooArray = fooArray; 11 } 12 13 public static void main(String[] args){ 14 Generic2<String> foo = new Generic2<String>(); 15 16 String[] str1 = {"hello", "world", "welcome"}; 17 String[] str2 = null; 18 19 foo.setFooArray(str1); 20 21 str2 = foo.getFooArray(); 22 23 for(int i = 0; i < str2.length; i++){ 24 System.out.println(str2[i]); 25 } 26 } 27 }
打印输出:
hello
world
welcome
SimpleCollection.java
1 public class SimpleCollection<T>{ 2 private T[] objArr; 3 4 private int index = 0; 5 6 public SimpleCollection(){ 7 objArr = (T[])new Object[10]; 8 //这个时候编译器会有一个警告: 9 //Type safety: Unchecked cast from Object[] to T[] 10 //这个时候老师领着看的ArrayList的源码中的get()方法 11 12 //objArr = new T[10]; 13 //报错:Cannot create a generic array of T 14 //语法上不允许这样创建一个泛型数组.这个时候怎么办? 15 //只能用Object类型. 16 17 } 18 19 public SimpleCollection(int capacity){ 20 objArr = (T[])new Object[capacity]; 21 } 22 23 public void add(T t){ 24 objArr[index++] = t; 25 } 26 27 public int getLength(){ 28 return this.index; 29 } 30 31 public T get(int i){ 32 return objArr[i]; 33 } 34 35 public static void main(String[] args){ 36 SimpleCollection<Integer> c = new SimpleCollection<Integer>(); 37 38 for(int i = 0; i < 10; i++){ 39 c.add(new Integer(i)); 40 } 41 42 for(int i = 0; i < 10; i++){ 43 Integer in = c.get(i); 44 45 System.out.println(in); 46 } 47 } 48 }
打印输出:1~9
ArrayListTest.java
1 public class ArrayListTest{ 2 public static void main(String[] args){ 3 List<String> list = new ArrayList<String>(); 4 5 list.add("a"); 6 list.add("b"); 7 list.add("c"); 8 list.add("d"); 9 //第一种遍历 10 for(int i = 0; i < list.size(); i++){ 11 String value = list.get(i); 12 System.out.println(value); 13 } 14 15 //第二种:使用迭代器 16 for(Iterator<String> iter = list.iterator(); iter.hasNext();){ 17 String value = iter.next(); 18 System.out.println(value); 19 } 20 } 21 }
打印输出:两次a b c d
SetTest.java
1 package cn.shengsiyuan.jdk5; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 import java.util.Set; 6 7 public class SetTest{ 8 public static void main(String[] args){ 9 Set<String> set = new HashSet<String>(); 10 11 set.add("aa"); 12 set.add("bb"); 13 set.add("cc"); 14 15 for (Iterator<String> iter = set.iterator(); iter.hasNext();){ 16 String value = iter.next(); 17 System.out.println(value); 18 } 19 20 System.out.println("----------------"); 21 22 Set<People> set2 = new HashSet<People>(); 23 24 set2.add(new People("zhangsan", 20, "beijing")); 25 set2.add(new People("lisi", 30, "shanghai")); 26 set2.add(new People("wangwu", 40, "tianjin")); 27 28 for(Iterator<People> iter = set2.iterator(); iter.hasNext();){ 29 People people = iter.next(); 30 31 String name = people.getName(); 32 int age = people.getAge(); 33 String address = people.getAddress(); 34 35 System.out.println(name + "," + age + "," + address); 36 } 37 } 38 } 39 40 class People{ 41 private String name; 42 43 private int age; 44 45 private String address; 46 47 public People(String name, int age, String address){ 48 this.name = name; 49 this.age = age; 50 this.address = address; 51 52 } 53 54 public int hashCode(){ 55 final int prime = 31; 56 int result = 1; 57 result = prime * result + ((address == null) ? 0 : address.hashCode()); 58 result = prime * result + age; 59 result = prime * result + ((name == null) ? 0 : name.hashCode()); 60 return result; 61 } 62 63 public boolean equals(Object obj){ 64 if (this == obj) 65 return true; 66 if (obj == null) 67 return false; 68 if (getClass() != obj.getClass()) 69 return false; 70 People other = (People) obj; 71 if (address == null){ 72 if (other.address != null) 73 return false; 74 } 75 else if (!address.equals(other.address)){ 76 return false; 77 } 78 if (age != other.age){ 79 return false; 80 } 81 if (name == null){ 82 if (other.name != null){ 83 return false; 84 } 85 } 86 else if (!name.equals(other.name)){ 87 return false; 88 } 89 return true; 90 } 91 92 public String getName(){ 93 return name; 94 } 95 96 public void setName(String name){ 97 this.name = name; 98 } 99 100 public int getAge(){ 101 return age; 102 } 103 104 public void setAge(int age){ 105 this.age = age; 106 } 107 108 public String getAddress(){ 109 return address; 110 } 111 112 public void setAddress(String address){ 113 this.address = address; 114 } 115 }
aa
bb
cc
----------------
wangwu,40,tianjin
zhangsan,20,beijing
lisi,30,shanghai
MapTest.java
1 public class MapTest{ 2 public static void main(String[] args){ 3 Map<String, String> map = new HashMap<String, String>(); 4 5 map.put("a", "aa"); 6 map.put("b", "bb"); 7 map.put("c", "cc"); 8 map.put("d", "dd"); 9 10 Set<String> set = map.keySet(); 11 12 for (Iterator<String> iter = set.iterator(); iter.hasNext();){ 13 String key = iter.next(); 14 String value = map.get(key); 15 16 System.out.println(key + ":" + value); 17 } 18 19 System.out.println("----------------------------------"); 20 21 Set<Map.Entry<String, String>> set2 = map.entrySet(); 22 23 for (Iterator<Map.Entry<String, String>> iter = set2.iterator(); iter 24 .hasNext();){ 25 Map.Entry<String, String> entry = iter.next(); 26 27 String key = entry.getKey(); 28 String value = entry.getValue(); 29 30 System.out.println(key + ":" + value); 31 } 32 } 33 }
d:dd
b:bb
c:cc
a:aa
----------------------------------
d:dd
b:bb
c:cc
a:aa
限制泛型可用类型:
在定义泛型类别时,预设可以使用任何的类型来实例化泛型类型中的类型,但是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类才能实例化该类型时,可以再定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口.
当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入.
ListGenericFoo.java
1 public class ListGenericFoo<T extends List> { 2 // 虽然这个地方List也是一个接口,但是在泛型中仍然要用extends.不能用implements. 3 // 不管面是类还是接口都要用extends 4 private T[] fooArray; 5 6 public T[] getFooArray() { 7 return fooArray; 8 } 9 10 public void setFooArray(T[] fooArray) { 11 this.fooArray = fooArray; 12 } 13 14 public static void main(String[] args) { 15 ListGenericFoo<LinkedList> foo1 = new ListGenericFoo<LinkedList>(); 16 ListGenericFoo<ArrayList> foo2 = new ListGenericFoo<ArrayList>(); 17 18 LinkedList[] linkedList = new LinkedList[10]; 19 20 foo1.setFooArray(linkedList); 21 22 ArrayList[] arrayList = new ArrayList[10]; 23 24 foo2.setFooArray(arrayList); 25 26 // ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>(); 27 // 报错,HashMap和List没有关系. 28 // Bound mismatch: The type HashMap is not a valid substitute for 29 // the bounded parameter <T extends List> of the type ListGenericFoo<T> 30 } 31 }
类型通配声明:
现在有这么一个需求,你希望哟u一个参考名称foo可以接受所有下面的实例:
foo = new Generic Foo<ArrayList>(); foo = new Generic Foo<LinkedList>();
简单的说,实例化类型持有者时,它必须是实现List的类别或其子类别,要定义这样一个名称,你可以使用"?"通配字符,并使用extends关键字限定类型持有者的形态.
GenericFoo<? extends List> foo = null; foo = new GenericFoo<ArrayList>(); foo = new GenericFoo<LinkedList>();
GenericTest.java
1 public class GenericTest<T>{ 2 private T foo; 3 4 public T getFoo(){ 5 return foo; 6 } 7 8 public void setFoo(T foo){ 9 this.foo = foo; 10 } 11 12 public static void main(String[] args){ 13 GenericTest<? extends List> ge = null; 14 15 ge = new GenericTest<ArrayList>(); 16 ge = new GenericTest<LinkedList>(); 17 18 //ge = new GenericTest<HashMap>(); 19 20 GenericTest<? super List> ge2 = null; 21 //这种super的非常少用,传递的值的类型必须是List的父类.... 22 ge2 = new GenericTest<Object>(); 23 24 //ge2 = new GenericTest<ArrayList>(); 25 //Type mismatch: cannot convert from GenericTest<ArrayList> to GenericTest<? super List> 26 27 GenericTest<String> ge3 = new GenericTest<String>(); 28 ge3.setFoo("hello world"); 29 //GenericTest<? extends Object> ge4 = ge3; 30 //如果后面是Object的话可以简写成一个问号"?" 31 GenericTest<?> ge4 = ge3; 32 System.out.println(ge4.getFoo());//打印输出:null 33 34 35 ge4.setFoo(null); 36 System.out.println(ge4.getFoo());//打印输出:null 37 //ge4.setFoo("welcome"); 38 //eclipse的提示错误信息:The method setFoo(capture#7-of ?) 39 //in the type GenericTest<capture#7-of ?> is not applicable for the arguments (String) 40 //这个错误信息不好理解.老师的解释是,当你上面GenericTest<? extends Object> ge4 的时候,编译器知道ge4的类型是 41 //Object或者其子类.但是当你进行ge4.setFoo("welcome");时候,当进行get的时候必须是一个String类型的,这个和泛型的 42 //的初衷想违背,所以是错误的. 43
使用<?>或是<? extends SomeClass>的声明方式,意味著您只能通过该名称來取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例,编译器不让您加入信息,理由是,如果可以加入信息的話,那么您就得記得取回的实例是什么类型,然后转换为原來的类型方可进行操作,这就失去了使用泛型的意义。