Java 2 平台标准版(J2SE 平台)5.0 在 Java 编程语言中引入了一些扩展。其中一个就是泛型的引入。泛型允许您在类型之上进行抽象。最常见的例子比如集合层级中的容器类型。在 J2SE 平台 5.0 发布前,在从集合中提取元素时,您必须将这个元素转换为该集合可存储元素的类型。这种方式既不方便,也不安全。编译器不会检查所转换的元素是否和集合类型保持一致,因此该转换会在运行时以失败告终。泛型为集合类型与编译器之间的通信提供了途径,这样便可在编译时对类型转换进行检查。知道集合的元素类型之后,编译器就能检查出您使用的集合是否一致,也能够对从集合中取出的值应用正确的转换。在本动手实验室中,您将学习如何通过在 NetBeans 4.0 软件的源编辑器中编写代码行来使用泛型,该编辑器会在发生编译错误时立即通知您。如果可能的话,也会介绍产生特定编译错误的原因。
预计时间:90 分钟
开始之前,需要在您的计算机中安装以下软件。
0. 如果还没有启动 NetBeans IDE,请启动它。
1. 创建一个新的 NetBeans 项目

| import java.util.ArrayList; import java.util.Date; import java.util.List; public class GenericsExample1 { public static void main(String[] args){ // Notice the type declaration <Integer> for the variable ai. // It specifies that this is not just an arbitrary ArrayList, // but a ArrayList of Integer, denoted as ArrayList<Integer>. ArrayList<Integer> ai = new ArrayList<Integer>(10); ai.add(0, new Integer(20)); ai.add(1, new Long(1234)); ai.add(2, new String("xyz")); ai.add(3, new Object()); Integer i = ai.get(0); String s = ai.get(0); Object o = ai.get(0); List<String> ls = new ArrayList<String>(10); ls.add(0, new String("abc")); ls.add(1, new Integer(2)); ls.add(2, new Date()); List<Object> lo = new ArrayList<Object>(10); lo.add(0, new Integer(20)); lo.add(1, new Long(1234)); lo.add(2, new String("xyz")); lo.add(3, new Object()); } } |

| // // Invoke various methods of a collection // List<Number> ln2 = new Vector<Number>(20); // Right click this line and select Fix Imports (Alt+Shift+F) ln2.add(0, new Integer(3)); ln2.add(1, new Long(1000L)); String s2 = new String("passion"); ln2.add(s2); Number n2 = ln2.get(0); Integer i2 = ln2.get(0); Boolean b2 = ln2.contains(new Integer(3)); Boolean b3 = ln2.contains(s2); System.out.println("b2="+b2); System.out.println("b3="+b3); // // Try to add an ArrayList of Integer to an ArrayList of Number // ArrayList<Integer> ai2 = new ArrayList<Integer> (10); ai2.add(new Integer(5)); ln2.addAll(ai2); // // Try to add an ArrayList of String to an ArrayList of Number // ArrayList<String> as2 = new ArrayList<String>(10); as2.add(new String("adventure")); ln2.addAll(as2); for (Number n: ln2){ System.out.println("number "+ n); } |
在本练习中,您将了解泛型的一个显著的行为,您也许要花些时间来适应它。最基本地,您将了解为什么 Java 编译器不允许以下代码而生成编译错误。
| ArrayList<Object> ao = new ArrayList<Integer>(); |
| import java.util.ArrayList; import java.util.List; import java.util.Vector; public class GenericsSubtyping { public static void main(String[] args){ // These should work ArrayList<Integer> ai = new ArrayList<Integer>(); ArrayList<String> as = new ArrayList<String>(); ArrayList<Object> ao1 = new ArrayList<Object>(); // There is no inheritance between type arguments ArrayList<Object> ao2 = new ArrayList<String>(); ArrayList<Object> ao3 = new ArrayList<Integer>(); // There is still inheritance relationship between classes List<String> ls = new ArrayList<String>(); List<Object> lo = new ArrayList<String>(); // There is still inheritance relationship between elements in a collection object List<Number> ln1 = new Vector<Number>(); List<Number> ln2 = new Vector<Integer>(); List<Number> ln3 = new ArrayList<Long>(); } } |
| List<String> ls = new ArrayList<String>(); //1 List<Object> lo = ls; //2 lo.add(new Object()); // 3 String s = ls.get(0); // 4: attempts to assign an Object to a String! ClassCastException would have to be thrown! |
| // // Assignment of collection with parameter types // List<Object> lo5 = new ArrayList<Integer>(); List<Object> lo6 = new Vector<Integer>(5); Collection<Object> co1 = new Vector<String>(); // Right-click this line and select Fix Imports first Collection<Object> co2 = new ArrayList<Integer> (10); Collection<Integer> ci1 = new ArrayList<Integer> (10); |
在本练习中,您了解了 ArrayList<String> 不是 一个 ArrayList<Object> 和为什么这成为问题的所在。
返回顶部| import java.util.ArrayList; import java.util.Collection; public class GenericsWildcard { static void printCollection(Collection<Object> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args){ // TODO code application logic here ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); } } |

| Collection<Object> c = new ArrayList<Integer> (10); // Compilation error |
| import java.util.ArrayList; import java.util.Collection; public class GenericsWildcard { static void printCollection(Collection<Integer> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args){ ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); } } |
| import java.util.ArrayList; import java.util.Collection; public class GenericsWildcard { static void printCollection(Collection<?> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args){ // TODO code application logic here ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); ArrayList<Long> l = new ArrayList<Long>(10); printCollection(l); ArrayList<String> s = new ArrayList<String>(10); printCollection(s); } } |
| Collection<?> c = new ArrayList<Integer> (10); // This code works c = new ArrayList<Long> (10); // This code works c = new ArrayList<String> (10); // This code works |
| import java.util.ArrayList; import java.util.Collection; public class GenericsBoundedWildcard { static void printCollection(Collection<? extends Number> c){ // Bounded wildcard for (Object o: c) System.out.println(o); } public static void main(String[] args){ ArrayList<Integer> a = new ArrayList<Integer>(10); printCollection(a); ArrayList<Long> l = new ArrayList<Long>(10); printCollection(l); ArrayList<String> s = new ArrayList<String>(10); printCollection(s); // Now compile error should occur } } |

| Collection<? extends Number> c = new ArrayList<Integer> (10); // This code works c = new ArrayList<Long> (10); // This code works c = new ArrayList<String> (10); // Compilation error |
| Collection<? extends Number> c3; c3 = new Vector<Integer>(); c3.add(new Integer(3)); c3.add(new Long(4L)); c3 = new Vector<String>(); c3 = new Vector<Long>(); c3 = new ArrayList<Date>(); Collection<? extends Object> c4; c4 = new Vector<Integer>(); c4 = new Vector<String>(); c4 = new Vector<Long>(); c4 = new ArrayList<Date>(); Collection<?> c5; c5 = new Vector<Integer>(); c5 = new Vector<String>(); c5 = new Vector<Long>(); c5 = new ArrayList<Date>(); |
| public class MyOwnGenericClass { public static void main(String[] args){ // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); // The following line of code should generate compile error // Pair<Number,String> p2 = new Pair<Number,String>(new Integer(4), new Integer(3)); System.out.println("first of p1 (right after creation)= " + p1.getFirst()); System.out.println("second of p2 (right after creation)= " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values)= " + p1.getFirst()); System.out.println("second of p1 (after setting values)= " + p1.getSecond()); } } |
| public class Pair<F, S> { F first; S second; public Pair(F f, S s){ first = f; second = s; } public void setFirst(F f){ first = f; } public F getFirst(){ return first; } public void setSecond(S s){ second = s; } public S getSecond(){ return second; } } |
| first of p1 (right after creation)= 5 second of p2 (right after creation)= Sun first of p1(after setting values)= 6 second of p1 (after setting values)= rises |
| public class MyOwnGenericClass { public static void main(String[] args){ // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); System.out.println("first of p1 (right after creation)= " + p1.getFirst()); System.out.println("second of p2 (right after creation)= " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values)= " + p1.getFirst()); System.out.println("second of p1 (after setting values)= " + p1.getSecond()); // Create an instance of Pair <F, S> class using wildcard type arguments. Number n2 = new Integer(15); String s2 = new String("again"); Pair<?, ?> p2 = new Pair<Number, String>(n2, s2); System.out.println("first of p2 = " + p2.getFirst()); System.out.println("second of p2 = " + p2.getSecond()); // Create an instance of Pair <F, S> class using wildcard with bounded type arguments. Number n3 = new Integer(25); String s3 = new String("and again!"); Pair<? extends String, ?> p3 = new Pair<String, String>(s3, s3); System.out.println("first of p3 = " + p3.getFirst()); System.out.println("second of p3 = " + p3.getSecond()); } } |
| first of p1 (right after creation)= 5 second of p2 (right after creation)= Sun first of p1(after setting values)= 6 second of p1 (after setting values)= rises first of p2 = 15 second of p2 = again first of p3 = and again! second of p3 = and again! |
| public class PairExtended <F, S, T> extends Pair<F, S> { T third; /** Creates a new instance of PairExtended */ PairExtended(F f, S s, T t){ super(f, s); third = t; } public T getThird(){ return third; } } |
| public class MyOwnGenericClass { public static void main(String[] args){ // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); System.out.println("first of p1 (right after creation)= " + p1.getFirst()); System.out.println("second of p2 (right after creation)= " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values)= " + p1.getFirst()); System.out.println("second of p1 (after setting values)= " + p1.getSecond()); // Create an instance of Pair <F, S> class using wildcard type arguments. Number n2 = new Integer(15); String s2 = new String("again"); Pair<?, ?> p2 = new Pair<Number, String>(n2, s2); System.out.println("first of p2 = " + p2.getFirst()); System.out.println("second of p2 = " + p2.getSecond()); // Create an instance of Pair <F, S> class using wildcard with bounded type arguments. Number n3 = new Integer(25); String s3 = new String("and again!"); Pair<? extends String, ?> p3 = new Pair<String, String>(s3, s3); System.out.println("first of p3 = " + p3.getFirst()); System.out.println("second of p3 = " + p3.getSecond()); // Create an instance of PairExtended<F, S, T> class with concrete type arguments, // <Number, String, Integer> Number n4 = new Long(3000L); String s4 = new String("james"); Integer i4 = new Integer(7); PairExtended<Number, String, Integer> pe4 = new PairExtended<Number, String, Integer>(n4, s4, i4); System.out.println("first of PairExtended = " + pe4.getFirst()); System.out.println("second of PairExtended = " + pe4.getSecond()); System.out.println("third of PairExtended = " + pe4.getThird()); } } |
| first of p1 (right after creation)= 5 second of p2 (right after creation)= Sun first of p1(after setting values)= 6 second of p1 (after setting values)= rises first of p2 = 15 second of p2 = again first of p3 = and again! second of p3 = and again! first of PairExtended = 3000 second of PairExtended = james third of PairExtended = 7 |
| import java.util.ArrayList; public class MyOwnGenericClass { public static void main(String[] args){ // Create an instance of Pair <F, S> class. Let's call it p1. Number n1 = new Integer(5); String s1 = new String("Sun"); Pair<Number,String> p1 = new Pair<Number,String>(n1, s1); System.out.println("first of p1 (right after creation)= " + p1.getFirst()); System.out.println("second of p2 (right after creation)= " + p1.getSecond()); // Set internal variables of p1. p1.setFirst(new Long(6L)); p1.setSecond(new String("rises")); System.out.println("first of p1(after setting values)= " + p1.getFirst()); System.out.println("second of p1 (after setting values)= " + p1.getSecond()); // Create an instance of Pair <F, S> class using wildcard type arguments. Number n2 = new Integer(15); String s2 = new String("again"); Pair<?, ?> p2 = new Pair<Number, String>(n2, s2); System.out.println("first of p2 = " + p2.getFirst()); System.out.println("second of p2 = " + p2.getSecond()); // Create an instance of Pair <F, S> class using wildcard with bounded type arguments. Number n3 = new Integer(25); String s3 = new String("and again!"); Pair<? extends String, ?> p3 = new Pair<String, String>(s3, s3); System.out.println("first of p3 = " + p3.getFirst()); System.out.println("second of p3 = " + p3.getSecond()); // Create an instance of PairExtended<F, S, T> class with concrete type arguments, // <Number, String, Integer> Number n4 = new Long(3000L); String s4 = new String("james"); Integer i4 = new Integer(7); PairExtended<Number, String, Integer> pe4 = new PairExtended<Number, String, Integer>(n4, s4, i4); System.out.println("first of PairExtended = " + pe4.getFirst()); System.out.println("second of PairExtended = " + pe4.getSecond()); System.out.println("third of PairExtended = " + pe4.getThird()); // Create an instance of PairExtended<F. S, T> class with // with ArrayList<E> as a third type argument. ArrayList<Integer> ar4 = new ArrayList<Integer>(); // Right-click this line and select Fix Imports first ar4.add(6000); ar4.add(7000); PairExtended<Number, String, ArrayList<Integer>> pe5 = new PairExtended<Number, String, ArrayList<Integer>>(n4, s4, ar4); System.out.println("first of PairExtended with ArrayList = " + pe5.getFirst()); System.out.println("second of PairExtended with ArrayList = " + pe5.getSecond()); System.out.println("third of PairExtended with ArrayList = " + pe5.getThird()); } } |
| first of p1 (right after creation)= 5 second of p2 (right after creation)= Sun first of p1(after setting values)= 6 second of p1 (after setting values)= rises first of p2 = 15 second of p2 = again first of p3 = and again! second of p3 = and again! first of PairExtended = 3000 second of PairExtended = james third of PairExtended = 7 first of PairExtended with ArrayList = 3000 second of PairExtended with ArrayList = james third of PairExtended with ArrayList = [6000, 7000] |
关于类型擦除的两个要点的
| import java.util.ArrayList; import java.util.Collection; import java.util.List; public class TypeErasure { static void printCollection(Collection<? extends Number> c){ for (Object o: c) System.out.println(o); } public static void main(String[] args){ // Display class information of the various ArrayList instances ArrayList<Integer> ai = new ArrayList<Integer>(); System.out.println("Class of ArrayList<Integer> = " + ai.getClass()); List<Integer> li = new ArrayList<Integer>(); System.out.println("Class of List<Integer> = " + li.getClass()); ArrayList<String> as = new ArrayList<String>(); System.out.println("Class of ArrayList<String> = " + as.getClass()); ArrayList ar = new ArrayList(); System.out.println("Class of ArrayList = " + ar.getClass()); // Check if two ArrayList instances with different type parameters // (one with Integer and the other with String)share the same class (bytecode). // Boolean b1 = (ai.getClass()== as.getClass()); System.out.println("Do ArrayList<Integer> and ArrayList<String> share same class? " + b1); // Check if two ArrayList instances with different type parameters // (one with Integer and the other with raw type)share the same class (bytecode). // Boolean b2 = (ai.getClass()== ar.getClass()); System.out.println("Do ArrayList<Integer> and ArrayList (raw type)share same class? " + b2); } } |
| Class of ArrayList<Integer> = class java.util.ArrayList Class of List<Integer> = class java.util.ArrayList Class of ArrayList<String> = class java.util.ArrayList Class of ArrayList = class java.util.ArrayList Do ArrayList<Integer> and ArrayList<String> share same class? true Do ArrayList<Integer> and ArrayList (raw type)share same class? true |
1. 创建一个新的 NetBeans 项目
| import java.util.List; import java.util.Vector; public class TypeErasure2 { public static void main(String[] args){ // // Get class and type information of a collection class // List<Number> ln5 = new Vector<Number>(20); Class c3 = ln5.getClass(); // Right-click this line and select Fix Imports first System.out.println("Class of List<Number> =" + c3); Class [] c4 = c3.getInterfaces(); // Right-click this line and select Fix Imports first for (Class c: c4){ System.out.println("Interface = " + c); } Class c5 = c3.getSuperclass(); System.out.println("Superclass = " + c5); } } |
| Class of List<Number> =class java.util.Vector Interface = interface java.util.List Interface = interface java.util.RandomAccess Interface = interface java.lang.Cloneable Interface = interface java.io.Serializable Superclass = class java.util.AbstractList |
| import java.util.LinkedList; import java.util.List; public class GenericsInteroperability { public static void main(String[] args){ List<String> ls = new LinkedList<String>(); List lraw = ls; lraw.add(new Integer(4)); String s = ls.iterator().next(); } } |
| Compiling 1 source file to C:\javase5generics\samples\GenericsInteroperability\build\classes Note: C:\javase5generics\samples\GenericsInteroperability\src\GenericsInteroperability.java uses unchecked or unsafe operations. Note:Recompile with -Xlint:unchecked for details. |

| import java.util.LinkedList; import java.util.List; public class GenericsInteroperability { public static void main(String[] args){ List<String> ls = new LinkedList<String>(); //List lraw = ls; //lraw.add(new Integer(4)); List<String> ls2 = ls; ls2.add(new Integer(4)); // Compile error String s = ls.iterator().next(); } } |
