JDK5新特性之一“泛型”小结
JDK5新特性之一“泛型”总结
泛型是JDK1.5中一个最重要的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastException的可能。
在JDK1.5中,你可以声明一个集合将接收/返回的对象的类型。
泛型特点:只要编译的时候没有问题,执行的时候肯定没有问题。
泛型之前:
类别定义时的逻辑完全一样,只是里面成员变量的类型不同。
如果需要多个相似的类,需要定义多个文件,不同的只是变量的类型,而逻辑是完全一样的。
以后使用集合的时候必须要使用泛型(可以避免很多强制类型转换)
迭代器迭代过程中迭代器也要加上泛型
以下是各种集合类在遍历的时候使用泛型的标准写法,以后把这个作为标准都这么写:
现在您有这么一个需求,您希望有一个参考名称foo可以接受下面所有的实例。
Foo = new GenericFoo<ArrayList>();
Foo = new GenericFoo<LinkedList>();
简单的说,实例化类型持有者时,它必须是实现List的类别或其子类别,要定义这样一个名称,您可以使用‘?’通配字元,并使用“extends”关键字限定类型持有者的型态。
在定义泛型类别时,预设可以使用任何的类型来实例化泛型类型中的类型,的那是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口。比如List<T extends List>,需要注意的是这里不管是类还是接口都要用extends关键字。
当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入。
使用<?>或是<? Extends SomeClass>的声明方式,意味着您只能通过该名称来取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例,编译器不让您加入信息,理由是,如果可以加入信息的话,那么您就得记得取回的实例是什么类型,然后转换为原来的类型方可进行操作,这就失去了使用泛型的意义。
重点比较下面两个类中泛型使用的各种情况,下面这两种情况有的时候很难区分,需要重点仔细查看这两个类:
泛型是JDK1.5中一个最重要的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastException的可能。
在JDK1.5中,你可以声明一个集合将接收/返回的对象的类型。
泛型特点:只要编译的时候没有问题,执行的时候肯定没有问题。
泛型之前:
类别定义时的逻辑完全一样,只是里面成员变量的类型不同。
如果需要多个相似的类,需要定义多个文件,不同的只是变量的类型,而逻辑是完全一样的。
以后使用集合的时候必须要使用泛型(可以避免很多强制类型转换)
迭代器迭代过程中迭代器也要加上泛型
以下是各种集合类在遍历的时候使用泛型的标准写法,以后把这个作为标准都这么写:
package com.shengshiyuan4; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ArrayListTest { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); for (int i = 0; i < list.size(); i++) { String value = list.get(i); System.out.println(value); } for (Iterator<String> iter = list.iterator(); iter.hasNext();) { String value = iter.next(); System.out.println(value); } } }
package com.shengshiyuan4; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class SetTest { public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("aa"); set.add("bb"); set.add("cc"); for (Iterator<String> iter = set.iterator(); iter.hasNext();) { String value = iter.next(); System.out.println(value); } System.out.println("--------------------------------"); Set<People> set2 = new HashSet<People>(); set2.add(new People("zhangsan", 20, "beijing")); set2.add(new People("lishi", 30, "shanghai")); set2.add(new People("wangwu", 40, "guangzhou")); for (Iterator<People> iter = set2.iterator(); iter.hasNext();) { People people = iter.next(); String name = people.getName(); String address = people.getAddress(); int age = people.getAge().intValue(); System.out.println(name + "," + age + "," + address); } } } class People { private String name; private Integer age; private String address; public People(String name, Integer age, String address) { this.name = name; this.age = age; this.address = address; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((address == null) ? 0 : address.hashCode()); result = prime * result + ((age == null) ? 0 : age.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final People other = (People) obj; if (address == null) { if (other.address != null) return false; } else if (!address.equals(other.address)) return false; if (age == null) { if (other.age != null) return false; } else if (!age.equals(other.age)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
package com.shengshiyuan4; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class MapTest { public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(); map.put("1", "aa"); map.put("2", "bb"); map.put("3", "cc"); Set<String> set = map.keySet(); for (Iterator<String> iter = set.iterator(); iter.hasNext();) { String key = iter.next(); String value = map.get(key); System.out.println(key + ";" + value); } Set<Map.Entry<String, String>> set2 = map.entrySet(); for (Iterator<Map.Entry<String, String>> iter = set2.iterator(); iter .hasNext();) { Map.Entry<String, String> entry = iter.next(); String key = entry.getKey(); String value = entry.getValue(); System.out.println(key + ";" + value); } } }
现在您有这么一个需求,您希望有一个参考名称foo可以接受下面所有的实例。
Foo = new GenericFoo<ArrayList>();
Foo = new GenericFoo<LinkedList>();
简单的说,实例化类型持有者时,它必须是实现List的类别或其子类别,要定义这样一个名称,您可以使用‘?’通配字元,并使用“extends”关键字限定类型持有者的型态。
在定义泛型类别时,预设可以使用任何的类型来实例化泛型类型中的类型,的那是如果想要限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口。比如List<T extends List>,需要注意的是这里不管是类还是接口都要用extends关键字。
当没有指定泛型继承的类型或接口时,默认使用T extends Object,所以默认情况下任何类型都可以作为参数传入。
使用<?>或是<? Extends SomeClass>的声明方式,意味着您只能通过该名称来取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例,编译器不让您加入信息,理由是,如果可以加入信息的话,那么您就得记得取回的实例是什么类型,然后转换为原来的类型方可进行操作,这就失去了使用泛型的意义。
重点比较下面两个类中泛型使用的各种情况,下面这两种情况有的时候很难区分,需要重点仔细查看这两个类:
package com.shengshiyuan4; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; //定义的时候没有明确泛型类型的范围 public class GenericTest<T> { private T foo; public T getFoo() { return foo; } public void setFoo(T foo) { this.foo = foo; } public static void main(String[] args) { // 表示ge是一个空的引用,它的类型是GenericTest,并且里面的泛型可以是实现了List接口的类型 // 申明引用变量的时候,表示这个引用可以指向什么类型的一个对象,表示可以指向类型为GenericTest的类并且里面的泛型类型必须实现了List接口 // 表示可以指向的一个泛型对象的类别到底是什么(在使用泛型的时候引用本身到底是什么类型的,这种方式并没有限定类里面的泛型是什么类型的,不像下面那种方式在开始就限定了) GenericTest<? extends List> ge = null; ge = new GenericTest<ArrayList>(); ge = new GenericTest<LinkedList>(); GenericTest<? extends Map> ge2 = null; ge2 = new GenericTest<HashMap>(); ge2 = new GenericTest<TreeMap>(); // 表示ge3可以指向GenericTest对象,里面的泛型要在继承层次当中位于List上面(这个用的比较少) GenericTest<? super List> ge3 = null; ge3 = new GenericTest<Collection>(); GenericTest<String> ge4 = new GenericTest<String>(); ge4.setFoo("hello world"); GenericTest<? extends Object> ge5 = ge4; System.out.println(ge5.getFoo()); ge5.setFoo(null); System.out.println(ge5.getFoo()); // 下面这种用法是错误的,原因是使用<?>或是<? Extends SomeClass>的声明方式,意味着您只能通过该名称来取得所参考实例的信息,或者是移除某些信息,但不能增加它的信息,因为只知道当中放置的是SomeClass的子类,但不确定是什么类的实例,编译器不让您加入信息,理由是,如果可以加入信息的话,那么您就得记得取回的实例是什么类型,然后转换为原来的类型方可进行操作,这就失去了使用泛型的意义。 // ge5.setFoo("welcome"); } }
package com.shengshiyuan4; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; //申明定义类的时候就指定好泛型类型的范围 //表示在构建这个泛型对象的时候具体的泛型类别可以是什么样的类型(定义类的时候就指定好了泛型的类别) public class ListGenericFoo<T extends List> { private T[] fooArray; public T[] getFooArray() { return fooArray; } public void setFooArray(T[] fooArray) { this.fooArray = fooArray; } public static void main(String[] args) { ListGenericFoo<LinkedList> foo1 = new ListGenericFoo<LinkedList>(); ListGenericFoo<ArrayList> foo2 = new ListGenericFoo<ArrayList>(); LinkedList[] linkedList = new LinkedList[10]; foo1.setFooArray(linkedList); ArrayList[] arrayList = new ArrayList[10]; foo2.setFooArray(arrayList); // 下面这种写法就是错误的 // ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>(); } }