示例:
1 public class Apple { 2 private static long counter; 3 private final long id = counter++; 4 5 public long id(){ 6 return id; 7 } 8 }
1 public class Orange { 2 3 }
1 public class ApplesAndOrangesWithoutGenerics { 2 @SuppressWarnings({ "rawtypes", "unchecked" }) 3 public static void main(String[] args) { 4 //定义一个ArrayList容器, 不指定其类型 5 ArrayList apples = new ArrayList(); 6 for (int i = 0; i < 3; i++) { 7 apples.add(new Apple()); 8 } 9 10 apples.add(new Orange()); 11 12 //此时, apples容器中存在4个对象, 其中前三个为Apple类型, 最后一个为Orange类型 13 for (int i = 0; i < apples.size(); i++) { 14 //get()方法取值时, 得到的只是Object的引用, 必须将其强制转型为Apple, 否则编译错误 15 //当试图将Orange对象转型为Apple时, 发生类型转换异常 16 System.out.println(((Apple)apples.get(i)).id()); 17 /* 18 * output: 19 * 0 20 * 1 21 * 2 22 * */ 23 } 24 } 25 }
在本例中,因为ArrayList保存的是Object,所以可以将Apple对象和Orange对象放进容器中,当在使用ArrayList的get()方法来取出Apple对象时,得到的只是Object的引用,必须将其转型为Apple,因此,需在调用Apple的id()方法之前,强制进行转型,否则,
就会得到编译错误。
刚才声明容器时没有预先定义类型,默认为Object,现在使用预定义泛型来看看:
1 public class ApplesAndOrangesWithoutGenerics2 { 2 public static void main(String[] args) { 3 //定义一个保存Apple对象的ArrayList, 尖括号括起来的是类型参数 4 //它指定了这个容器示例可以保存的类型, 通过使用泛型, 就可以在编译器放置将错误类型的对象放置到容器中 5 ArrayList<Apple> apples = new ArrayList<Apple>(); 6 for (int i = 0; i < 3; i++) { 7 apples.add(new Apple()); 8 } 9 10 //apples.add(new Orange()); 编译器可以阻止将Orange放置到apples中 11 12 for (int i = 0; i < apples.size(); i++) { 13 System.out.println(apples.get(i).id()); 14 } 15 16 for (Apple c : apples) { 17 System.out.println(c.id()); 18 } 19 20 /*output 21 * 0 22 * 1 23 * 2 24 * 0 25 * 1 26 * 2 27 * */ 28 } 29 }
我们注意到,定义了容器类型后,编译器可以阻止将Orange放置到apples中,因为此时Orange对象的类型与容器类型不匹配,发生编译错误;另外,将元素从容器中取出时,类型转换也不再时必须的了,因为容器知道自己保存的是什么类型,因此会在调用
get()时帮忙转型。