用代码说话:
- package orz.caikanxp;
- import java.util.ArrayList;
- import java.util.List;
- import org.junit.Test;
- public class TestGeneric {
- // 创建一个ArrayList对象
- private Object list = new ArrayList();
- // 声明3个类型参数各不相同的List变量引用。
- private List oList = (List) this.list;
- private List<String> sList = (List<String>) this.list;
- private List<Boolean> bList = (List<Boolean>) this.list;
- // 用于测试的3种不同类型的数据
- private Object o = new Object();
- private String s = "hello";
- private Boolean b = true;
- // 无编译错误,有警告——未提供类型参数
- @Test
- public void testListAdd() throws Exception {
- this.oList.add(o);
- this.oList.add(s);
- this.oList.add(b);
- }
- // 注释的语句有会有编译错误——类型不匹配
- @Test
- public void testStringListAdd() throws Exception {
- // this.sList.add(o);
- this.sList.add(s);
- // this.sList.add(b);
- }
- // 注释的语句有会有编译错误——类型不匹配
- @Test
- public void testBooleanListAdd() throws Exception {
- // this.bList.add(o);
- // this.bList.add(s);
- this.bList.add(b);
- }
- // 编译运行均正常
- @Test
- public void testListGet() throws Exception {
- // 先往ArrayList对象中添加测试数据
- this.testListAdd();
- // 取出数据并使用Object类型变量引用。
- Object o0 = this.oList.get(0);
- Object o1 = this.oList.get(1);
- Object o2 = this.oList.get(2);
- System.out.println("testListGet");
- System.out.println(o0.getClass());
- System.out.println(o1.getClass());
- System.out.println(o2.getClass());
- System.out.println();
- }
- // 编译正常,运行时抛出异常——java.lang.ClassCastException
- // 引用变量的声明类型为String,取出数据的实际运行时类型为Object
- @Test
- public void testStringListGet0() throws Exception {
- this.testListAdd();
- String s0 = this.sList.get(0);
- System.out.println("testStringListGet0");
- System.out.println(s0.getClass());
- System.out.println();
- }
- // 编译运行均正常
- // 引用的变量声明类型和取出数据的实际运行时类型均为String
- @Test
- public void testStringListGet1() throws Exception {
- this.testListAdd();
- String s1 = this.sList.get(1);
- System.out.println("testStringListGet1");
- System.out.println(s1.getClass());
- System.out.println();
- }
- // 编译正常,运行时抛出异常——java.lang.ClassCastException
- // 引用变量的声明类型为String,取出数据的实际运行时类型为Boolean
- @Test
- public void testStringListGet2() throws Exception {
- this.testListAdd();
- String s2 = this.sList.get(2);
- System.out.println("testStringListGet2");
- System.out.println(s2.getClass());
- System.out.println();
- }
- // 编译运行均正常
- // 引用变量的声明类型为根超类Object,任何实际运行时类型都能引用
- @Test
- public void testStringListGetObject() throws Exception {
- this.testListAdd();
- Object o0 = this.sList.get(0);
- Object o1 = this.sList.get(1);
- Object o2 = this.sList.get(2);
- System.out.println("testStringListGetObject");
- System.out.println(o0.getClass());
- System.out.println(o1.getClass());
- System.out.println(o2.getClass());
- System.out.println();
- }
- // 要从List<String>中取出Boolean数据该怎么办呢?
- @Test
- public void testStringListGetBoolean() throws Exception {
- this.testListAdd();
- // 这种强制转换行不通,方法返回的声明类型是String,引用变量的类型是Boolean
- // 编译器会检查发现Boolean不是String子类,没有继承关系不允许强制转换。
- // Boolean b2 = (Boolean)this.sList.get(2);
- // 可以通过这个办法回避囧……
- // 先用临时根超类变量引用
- Object o2 = this.sList.get(2);
- // 再对临时根超类变量进行转换
- Boolean b2 = (Boolean) o2;
- // 结果证明取出的值确实是Boolean类型
- System.out.println("testStringListGetBoolean");
- System.out.println(b2.getClass());
- System.out.println();
- }
- }
JUnit4测试输出结果:
- testListGet
- class java.lang.Object
- class java.lang.String
- class java.lang.Boolean
- testStringListGet1
- class java.lang.String
- testStringListGetObject
- class java.lang.Object
- class java.lang.String
- class java.lang.Boolean
- testStringListGetBoolean
- class java.lang.Boolean
注意:
上面的代码第11行创建的ArrayList对象未指定类型参数;但是即使指定了类型参数,运行的结果也是完全相同的!
因为创建的对象与“类型参数”是无关的,唯一的不同是编译时返回的“声明类型”。
甚至可以把11行换成如下语句,运行的结果和之前也是完全一致的,而不会报错:
- private Object list = new ArrayList<java.util.Date>();
结论:
Java5中泛型仅仅是编译时检查的,要小心使用哦。