泛型:
泛型是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.String28 }29 }
定义泛型类别:
如果使用泛型,只要代码在编译时没有出现警告,就不会遇到运行时ClassCastException
所谓泛型就是变量的类型参数化(不是变量本身,是变量的类型).
GenericFoo.java
1 public class GenericFoo{ 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 foo1 = new GenericFoo ();14 GenericFoo foo2 = new GenericFoo ();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);//打印输出:false23 System.out.println(i);//打印输出:324 25 //foo1 = foo2;26 //报错Type mismatch: cannot convert from GenericFoo to GenericFoo 27 28 GenericFoo a = new GenericFoo();29 a.setFoo("hello");30 31 String str = (String)a.getFoo();32 System.out.println(str);//输出:hello33 }34 }
Generic.java
1 public class Generic{ 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 foo = new Generic ();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
falseGeneric2.java
1 public class Generic2{ 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 foo = new Generic2 ();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
worldwelcomeSimpleCollection.java
1 public class SimpleCollection{ 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 T14 //语法上不允许这样创建一个泛型数组.这个时候怎么办?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 c = new SimpleCollection ();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 Listlist = new ArrayList (); 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 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 Setset = new HashSet (); 10 11 set.add("aa"); 12 set.add("bb"); 13 set.add("cc"); 14 15 for (Iterator iter = set.iterator(); iter.hasNext();){ 16 String value = iter.next(); 17 System.out.println(value); 18 } 19 20 System.out.println("----------------"); 21 22 Set set2 = new HashSet (); 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 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
bbcc----------------wangwu,40,tianjinzhangsan,20,beijinglisi,30,shanghaiMapTest.java
1 public class MapTest{ 2 public static void main(String[] args){ 3 Mapmap = new HashMap (); 4 5 map.put("a", "aa"); 6 map.put("b", "bb"); 7 map.put("c", "cc"); 8 map.put("d", "dd"); 9 10 Set set = map.keySet();11 12 for (Iterator 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 > set2 = map.entrySet();22 23 for (Iterator > iter = set2.iterator(); iter24 .hasNext();){25 Map.Entry 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:bbc:cca:aa----------------------------------d:ddb:bbc:cca:aa限制泛型可用类型:
在定义泛型类别时,预设可以使用任何的类型来实例化泛型类型中的类型,但是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类才能实例化该类型时,可以再定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口.
当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入.
ListGenericFoo.java
1 public class ListGenericFoo{ 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 foo1 = new ListGenericFoo ();16 ListGenericFoo foo2 = new ListGenericFoo ();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 foo3 = new ListGenericFoo ();27 // 报错,HashMap和List没有关系.28 // Bound mismatch: The type HashMap is not a valid substitute for29 // the bounded parameter of the type ListGenericFoo 30 }31 }
类型通配声明:
现在有这么一个需求,你希望哟u一个参考名称foo可以接受所有下面的实例:
foo = new Generic Foo();foo = new Generic Foo ();
简单的说,实例化类型持有者时,它必须是实现List的类别或其子类别,要定义这样一个名称,你可以使用"?"通配字符,并使用extends关键字限定类型持有者的形态.
GenericFoo foo = null;foo = new GenericFoo();foo = new GenericFoo ();
GenericTest.java
1 public class GenericTest{ 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 ge = null;14 15 ge = new GenericTest ();16 ge = new GenericTest ();17 18 //ge = new GenericTest ();19 20 GenericTest ge2 = null;21 //这种super的非常少用,传递的值的类型必须是List的父类....22 ge2 = new GenericTest
使用<?>或是<? extends SomeClass>的声明方式,意味著您只能通过该名称來取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例,编译器不让您加入信息,理由是,如果可以加入信息的話,那么您就得記得取回的实例是什么类型,然后转换为原來的类型方可进行操作,这就失去了使用泛型的意义。