JavaSE第五十四讲:自定义泛型与泛型的常见陷阱
2012-12-27 10:16
357 查看
结合上一讲泛型的内容,现在我们来通过程序掌握两个泛型的使用
编译执行结果:
-20
false
【说明】:为什么下面两种在main函数中的写法得出的结果是一样的呢?那种体现泛型呢?不明白的地方!
[方式1]foo.setFoo1(-20);
foo.setFoo2(false);
[方式2]foo.setFoo1(new Integer(-20));
foo.setFoo2(new Boolean(false));
数组泛型的使用
hello
world
welcome
使用泛型实现一个简单的集合,模仿ArrayList的使用方式
【说明】这边查看ArrayList源码中泛型的使用方式,
ArrayList定义为Object[],那它取出来的时候也必须是Object类型的数组(Object[]),查看get()方法。
【总结我的泛型定义与ArrayList的不同】ArrayList 定义为数组类型,取的时候转化为泛型,而我们的设计是定义为泛型,构造的时候强制转换为泛型,取的时候就不需要转了。
写一个泛型嵌套泛型的例子
-10
查看JDK Doc文档中的集合,可以发现从JDK5.0开始,集合都改成泛型的方式去实现了,所以我们在将来写集合的时候要使用泛型去实现,现在我们就用这种方式去写几个集合的例子。
【说明】:可能有人会觉得,如果我不使用泛型的话,我可以往集合里面放置任何类型的对象,但是如果使用了泛型,那只能使用指定的类型,但是终究这种设计是不好的,集合通常就是用来放置相同类型的对象,如果有两个不同的类型对象,那就声明两个集合。泛型官方文档表示是为了避免编译类转换异常的方式,但我个人认为它是一种规范代码,提高可读性的很好方式。
程序一:List的泛型方式实现
编译执行结果:a b c d a b c d
程序二:Set的泛型方式实现
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
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; //数组的索引,表示当前有多少个数组 //默认数组长度,定义为10 public 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()方法,不懂请查看前几讲内容 */ @Override public 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; } @Override public 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
相关文章推荐
- Java 理论和实践: 了解泛型(第一次使用泛型的用户的常见陷阱)
- [javase]自定义泛型比较器 排序
- JavaSE第一百零二讲:synchronized关键字常见陷阱深度剖析
- JavaSE第八十五讲:内部类深度剖析及常见使用陷阱
- 给创始人的建议:需要避免的常见创业陷阱
- 20条常见的编码陷阱
- Spring JdbcTemplate实现通用的泛型dao四:通用自定义转换到JavaBean的RowMapper实现
- NIO常见的陷阱解析
- 【JavaSE笔记】Java常见细节性问题(三)_二维数组
- 技术文章 | 深度学习的这些坑你都遇到过吗?神经网络11大常见陷阱及应对方法
- java中的泛型的一些常见例子
- 数组自定义排序、泛型
- Linux共享内存使用常见陷阱与分析
- Scala代码编写中常见的十大陷阱
- List(泛型)类型转换陷阱,hibernate 原生查询BigInteger 转 Long 出错问题
- 20条常见的编码陷阱 你中枪了没?
- 自定义view系列01--Android 屏幕的常见认识
- Java多线程编程的常见陷阱
- XCode: 添加自定义代码片段到Code Snippets Library(常见代码段高效使用)
- JAVASE----10----泛型