JavaSE第五十四讲:自定义泛型与泛型的常见陷阱

来源:互联网 发布:粉钥匙软件 编辑:程序博客网 时间:2024/05/22 01:41

结合上一讲泛型的内容,现在我们来通过程序掌握两个泛型的使用

package com.ahuier.jdk5;public class Generic<T1, T2> {private T1 foo1;private T2 foo2;public T1 getFoo1() {return foo1;}public void setFoo1(T1 foo1) {this.foo1 = foo1;}public T2 getFoo2() {return foo2;}public void setFoo2(T2 foo2) {this.foo2 = foo2;}public static void main(String[] args) {Generic<Integer, Boolean> foo = new Generic<Integer, Boolean>();/* * 这边两种不同的写法,得出的结果是一样的,为什么? *//*foo.setFoo1(-20);foo.setFoo2(false);*/foo.setFoo1(new Integer(-20));foo.setFoo2(new Boolean(false));/*Integer in = foo.getFoo1();Boolean b = foo.getFoo2();*/System.out.println(foo.getFoo1());System.out.println(foo.getFoo2());}}

编译执行结果:

-20
false

【说明】:为什么下面两种在main函数中的写法得出的结果是一样的呢?那种体现泛型呢?不明白的地方!

[方式1]foo.setFoo1(-20);

foo.setFoo2(false);

[方式2]foo.setFoo1(new Integer(-20));

foo.setFoo2(new Boolean(false));

数组泛型的使用

package com.ahuier.jdk5;public class Generic1<T> {private T[] fooArray;public T[] getFooArray() {return fooArray;}public void setFooArray(T[] fooArray) {this.fooArray = fooArray;}public static void main(String[] args) {Generic1<String> foo = new Generic1<String>();String[] str = {"hello", "world", "welcome"};foo.setFooArray(str);String[] str1 = foo.getFooArray();for(int i = 0; i < str1.length; i++){System.out.println(str1[i]);}}}
编译执行结果:

hello
world
welcome


使用泛型实现一个简单的集合,模仿ArrayList的使用方式

package com.ahuier.jdk5;public class SimCollection<T> {private T[] objArr;private int index = 0; //数组的索引,表示当前有多少个数组//默认数组长度,定义为10public SimCollection(){//objArr = new T[10] //这种写法是错误的,如果T是具体的某一种类型,则可以,对于数组来说,不能通过new的方式来创建一个泛型数组。/* * objArr = (T[])new Object[10];  * 这边会出现警告:Type safety: Unchecked cast from Object[] to T[] * 这边没有任何办法可以除去这个警告,查看ArrayList源代码,相同原理 */objArr = (T[])new Object[10]; }//自定义数组长度public SimCollection(int capacity){objArr = (T[])new Object[capacity];}public void add(T t){objArr[index++] = t;  //index表示数组索引,首个索引为0,++ 表示索引往后移动一个位置,下次就放在索引1的位置上}public int getLegth(){   return this.index;   //取出数组长度}public T get(int i){return objArr[i];    //取出数组中的元素}public static void main(String[] args) {SimCollection<Integer> c = new SimCollection<Integer>();//往数组中添加Integer类型数组for(int i = 0; i < 10; i++){c.add(new Integer(i));}for(int i = 0; i < c.getLegth(); i++){Integer in = c.get(i);System.out.println(in);}}}
编译执行结果:0 1 2 3 4 5 6 7 8 9

【说明】这边查看ArrayList源码中泛型的使用方式,

    /**     * The array buffer into which the elements of the ArrayList are stored.     * The capacity of the ArrayList is the length of this array buffer.     */    private transient Object[] elementData;
ArrayList中直接定义为Objcet[],而我们自定义的是T[],这边存在不同,继续接下来查看

ArrayList定义为Object[],那它取出来的时候也必须是Object类型的数组(Object[]),查看get()方法。

    public E get(int index) {RangeCheck(index);return (E) elementData[index];    }
return (E) elementData[index]; 这边它返回的时侯,已经强制类型转化为泛型 E。所以这边ArrayList的设计是定义的时候,用Object[],取出来的时候转化为泛型类别 E,而我们的设计是定义数组的时候就直接定义成泛型,所以在构造函数 objArr = (T[])new Object[10]; 里面就必须要进行强制类型转化。这就是我的设计与ArrayList的设计的差异性。

【总结我的泛型定义与ArrayList的不同】ArrayList 定义为数组类型,取的时候转化为泛型,而我们的设计是定义为泛型,构造的时候强制转换为泛型,取的时候就不需要转了。


写一个泛型嵌套泛型的例子

package com.ahuier.jdk5;public class WrapperFoo<T> {private GenericFoo3<T> foo;public GenericFoo3<T> getFoo() {return foo;}public void setFoo(GenericFoo3<T> foo) {this.foo = foo;}public static void main(String[] args) {GenericFoo3<Integer> foo = new GenericFoo3<Integer>();foo.setFoo(new Integer(-10));//将泛型做为类型传递过去WrapperFoo<Integer> wrapper = new WrapperFoo<Integer>();wrapper.setFoo(foo);GenericFoo3<Integer> g = wrapper.getFoo();System.out.println(g.getFoo());}}class GenericFoo3<T>{private T foo;public T getFoo() {return foo;}public void setFoo(T foo) {this.foo = foo;}}
编译执行结果:

-10


查看JDK Doc文档中的集合,可以发现从JDK5.0开始,集合都改成泛型的方式去实现了,所以我们在将来写集合的时候要使用泛型去实现,现在我们就用这种方式去写几个集合的例子。

【说明】:可能有人会觉得,如果我不使用泛型的话,我可以往集合里面放置任何类型的对象,但是如果使用了泛型,那只能使用指定的类型,但是终究这种设计是不好的,集合通常就是用来放置相同类型的对象,如果有两个不同的类型对象,那就声明两个集合。泛型官方文档表示是为了避免编译类转换异常的方式,但我个人认为它是一种规范代码,提高可读性的很好方式。

程序一:List的泛型方式实现

package com.ahuier.jdk5;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>();//查看Eclipse提示信息,add里面的内容只能加字符串了。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); //查看Eclipse提示信息,调用get(i)返回的也String类型,所以不需要进行强制类型转换了。System.out.println(value);}/* * 使用迭代器的时候泛型也是这么用的。 * 查看JDK Doc文档,它也是泛型,表示迭代目标集合的类型。 * 集合对象是String类型,所以迭代器泛型也是String */for(Iterator<String> iter = list.iterator(); iter.hasNext();){String value = iter.next(); //查看Eclipse提示信息,调用next()方法返回的是也是String类型,所以不需要进行强制类型转换了。System.out.println(value);}}}

编译执行结果:a b c d a b c d

程序二:Set的泛型方式实现

package com.ahuier.jdk5;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");set.add("dd");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", 10, "shanghai"));set2.add(new People("lisi", 20, "guangdong"));set2.add(new People("wangwu", 30, "beijing"));for(Iterator<People> iter = set2.iterator(); iter.hasNext();){People people = iter.next();//System.out.println(value);//这边打印出来不是内容值,使用getter() 和 setter()方法取。String name = people.getName();int age = people.getAge();String address = people.getAddress();System.out.println(name + "," + age + "," + address);}}}/* * 自定义一个类,实现set的泛型 */class People{private String name; private int age;private String address;public People(String name, int age, String address){this.name = name;this.age = age;this.address = address;}/* * 为了能够将其放入集合中,必须为它们实现hashCode()和equals()方法,不懂请查看前几讲内容 */@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((address == null) ? 0 : address.hashCode());result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;People other = (People) obj;if (address == null) {if (other.address != null)return false;} else if (!address.equals(other.address))return false;if (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}/* * 添加getter() 和 setter()方法,便于上面取值。 */public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}}
编译执行结果:

dd
aa
bb
cc
-----------------------------
wangwu,30,beijing
lisi,20,guangdong
zhangsan,10,shanghai


程序三:Map的泛型方式实现

package com.ahuier.jdk5;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) {/* * 查看JDK Doc文档,Map<K, V>是定义了两个泛型 */Map<String, String> map = new HashMap<String, String>();map.put("a", "aa");map.put("b", "bb");map.put("c", "cc");map.put("d", "dd");/* * Map的遍历有两种方式,参考之前所讲内容 *///法一:获取key,遍历key得到value值,注意key返回的也是用String类型变量接受。    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);    }        System.out.println("-------------------------");        //法二:调用entrySet()方法,获得一个Map.Entry对象    //调用entrySet()方法后,会返回一个Set对象,Set里面是一个一个的Map.Entry元素,Map.Entry元素封装了key和value的值,它们的字符串类型的,所以Map.Entry是一个泛型    Set<Map.Entry<String, String>> set2 = map.entrySet();    //这边迭代器也是一个泛型 Map.Entry<String,String>    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);    }}}
编译执行结果:

d:dd
b:bb
c:cc
a:aa
-------------------------
d:dd
b:bb
c:cc
a:aa



原创粉丝点击