泛型概述
在Java中存入容器中的对象再取出时需要转换类型,因为对象加入容器会被转换成Object类型,而取出时要转换成实际类型。但向 下类型转换都 是存在潜在危险的,因此应该尽量避免它们。
Java的泛型:
所谓泛型就是在定义(类、方法、形参、成员变量等等)的时候,指 定它们为通用类型,也就是数据类型可以是任意类型。
泛型为提高大型程序的类型安全和维护带来了很大的潜力。
使用泛型的目的:
· 努力将运行时异常转换成编译时的错误,减少运行时异常的数量。
· 解决模板编程的问题。
1. 泛型的声明:
在定义泛型类的时候,在<>中定义形式类型参数,例如:
Class TestJava<K, V>、Class TestList<E>、Class TestVector<T>,
其中
K:键,比如映射的键。
V:值,比如Set、List、Map中的值。
E:异常类。
T : 泛型。
在实例化泛型对象的时候,一定要在类名后面指定类型参数的值,如:
List<String> list = new ArrayList<String>():
2. 泛型的使用:
1>消除类型的转换:
下面是消除类型转换的例子:
<span style="font-size:14px;">import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; public class CollectionsTest { public static void main(String[] args) { // 声明ArrayList对象 ,且list中只能存储String类元素 List<String> list = new ArrayList<String>(); // 向数组列表中添加元素 list.add("1abc"); list.add("2def"); list.add("3hij"); list.add("4klm"); // 取得list元素并输出,无须类型转换 System.out.print("输出第四个元素:"); String str = list.get(3); System.out.println(str); System.out.println("\n输出列表中的所有元素:"); for (String s : list) { System.out.println(s); } System.out.println(); // 声明一个HashMap对象,指定键的类型为Integer、值的类型为String Map<Integer, String> map = new HashMap<Integer, String>(); // 向对象中添加元素 map.put(1, "zhao"); map.put(2, "qian"); map.put(3, "sun"); map.put(4, "li"); // 取得键集 Set<Integer> keys = map.keySet(); // 由键取得对应的值,并输出 System.out.println("输出: key=value"); for (Integer i : keys) { String value = map.get(i); System.out.println(i + "=" + value); } } }</span>
输出结果:
输出第四个元素:4klm
输出列表中的所有元素:
1abc
2def
3hij
4klm
输出: key=value
1=zhao
2=qian
3=sun
4=li
注:
·属性中使用集合时不指定泛型,默认为 <Object>,如定义属性: List<Object> list=null;
· 泛型不同的引用不能相互赋值。
· 加入集合中的对象类型必须与指定的泛型类型一一致。
2>限制泛型中类型参数的使用:
· <?>: 允许所有泛型的引用调用。
· <? Extends Number>: 只允许泛型为Number及Number子类的引用调用。
· <? Super Number>: 只允许泛型为Number及Number父类的引用调用。
· <? Extends Comparable>: 只允许泛型为实现Comparable接口的实现类的引用调用。
注:
· 方法参数中使用集合时不指定泛型默认为<?>.
· 方法参数中<? Extends Number&Comparable>这种修饰符是不 支持的。
下面的例子演示限制类型的参数的范围:
<span style="font-size:14px;">import java.util.ArrayList; import java.util.List; public class CollectionsTest { public static void main(String[] args) { List<String> l1 = new ArrayList<String>(); l1.add("China"); List<Object> l2 = new ArrayList<Object>(); l2.add(99); List<Number> l3 = new ArrayList<Number>(); l3.add(3.3); List<Integer> l4 = new ArrayList<Integer>(); l4.add(83); List<Double> l5 = new ArrayList<Double>(); l5.add(93.67); printView(l1);//String类型的泛型对象 printView(l2);//Object类型的泛型对象 printView(l3);//Number类型的泛型对象 printView(l4);//Integer类型的泛型对象 printView(l5);//Double类型的泛型对象 } //方法参数中使用集合时不指定泛型,默认为<?> @SuppressWarnings("rawtypes") private static void printView(List list) { for (Object o : list) { System.out.println(o); } } } </span>
输出结果:
China
99
3.3
83
93.67
(1)当上面例子中的方法变为:
<span style="font-size:14px;"> //允许所有的泛型的引用调用 @SuppressWarnings("rawtypes") private static void printView(List<?> list) { for (Object o : list) { System.out.println(o); } }</span>
时,输出结果:
China
99
3.3
83
93.67
可见输出结果是不变的。
(2)当上面例子中的方法变为:
<span style="font-size:14px;">//允许Number及Number的自类的引用调用 @SuppressWarnings("rawtypes") private static void printView(List<? extends Number> list) { for (Object o : list) { System.out.println(o); } }</span>
此时需要注释掉两行:
<span style="font-size:14px;"> // printView(l1);//String类型的泛型对象 // printView(l2);//Object类型的泛型对象</span>
运行,
输出结果:
3.3
83
93.67
(3)当上面例子的方法变为:
<span style="font-size:14px;"> //只允许实现了Comparable接口的类的引用调用 @SuppressWarnings("rawtypes") private static void printView(List<? extends Comparable> list) { for (Object o : list) { System.out.println(o); } }</span>
此时需要注释掉两行:
<span style="font-size:14px;">// printView(l2);//Object类型的泛型对象 // printView(l3);//Number类型的泛型对</span>
运行,
输出结果:
China
83
93.67
(4)当上面的例子的方法变为:
<span style="font-size:14px;">// 只允许Number和Number的父类的引用调用 @SuppressWarnings("rawtypes") private static void printView(List<? super Number> list) { for (Object o : list) { System.out.println(o); } } </span>
此时需要注释掉三行:
<span style="font-size:14px;">// printView(l1);// String类型的泛型对象 // printView(l4);// Integer类型的泛型对象 // printView(l5);// Double类型的泛型对象</span>
运行,
输出结果:
99
3.3
3>泛型的方法(也被称为Java中的多态):
在类的定义中添加一个形式类型参数列表,可以将类泛型化。方法也 可以被泛型化,不管它们所在的类是不是泛型化的。
泛型方法的格式为:
修饰符 泛型 返回类型 方法名 参数表 抛出的异常
泛型的样式有如下几种:
· <T>: 允许所以泛型的引用调用。
· <T extends Number>: 只允许泛型为Number及Number子类的引用调用。
· <T extends Comparable>: 只允许泛型为实现了Comparable接口的实现类的引用调用。
· <T extends Number&Comparable>: 只允许泛型为即是Number及Number子类又实现了Comparable几接口的
实现类的引用调用。
注:泛型方法中 <? super Number>这种修饰符是不支持的。
下面是泛型方法使用的例子:
<span style="font-size:14px;">import java.util.ArrayList; import java.util.List; public class CollectionsTest { public static void main(String[] args) { //声明各类的对象 List<String> l1 = new ArrayList<String>(); List<Object> l2 = new ArrayList<Object>(); List<Number> l3 = new ArrayList<Number>(); List<Integer> l4 = new ArrayList<Integer>(); List<Double> l5 = new ArrayList<Double>(); //创建各类的数组 String[] a1 = new String[1]; a1[0] = "a1"; Object[] a2 = new Object[1]; a2[0] = "Object"; Number[] a3 = new Number[1]; a3[0] = 3; Integer[] a4 = new Integer[1]; a4[0] = 4; Double[] a5 = new Double[1]; a5[0] = 5.5; //将相同类的数组copy到对象 copyFromArray(l1, a1); copyFromArray(l2, a2); copyFromArray(l3, a3); copyFromArray(l4, a4); copyFromArray(l5, a5); //显示对象元素 printView(l1); printView(l2); printView(l3); printView(l4); printView(l5); } //显示方法 private static void printView(List<?> l) { for (Object o : l) { System.out.println(o); } } //copy的方法 private static <T> void copyFromArray(List<T> l, T[] a) { for (T o : a) l.add(o); } }</span>
输出结果:
a1
Object
3
4
5.5
4>泛型类:
泛型类的写法:
<span style="font-size:14px;">class Person<E> { public void show(E e) { System.out.println(e); } public E get() { return null; } }</span>
编写泛型类的时候要注意:
· 静态方法中不能使用类的泛型,原因是泛型类中的泛型在创建类的对象时被替换成确定的类型。
静态方法可以通过类名直接访问,而Java是一种强类语言,没有类型的变量或对象是不允许存在的,
所以静态方法中不能使用类的泛型。
· 不要创建泛型类的对象,因为泛型类有可能是一个接口或抽象类,如果不是接口或抽象类则可以创建。
· 不能在Catch字句中使用泛型,因为编译时,如果try子句抛出的 是一检查的异常,编译器无法确定Catch能否不活这个异常。
下面是演示泛型类创建的技巧的例子:
类TestGenrics中的代码:
<span style="font-size:14px;">public class TestGenrics { public static void main(String[] args) { @SuppressWarnings({ "rawtypes" }) MyClass<?> test = new MyClass(); test.show(); MyClass<String> str = new MyClass<String>(); str.method("323"); str.show(); MyClass<Integer> i = new MyClass<Integer>(); i.method(323); i.show(); } } </span>
泛型类MyClass<T> 中的代码:
<span style="font-size:14px;"> class MyClass<T> { private T t; public void method(T t) { this.t = t; } public T method1() { return null; } public void show(){ System.out.println(t); } }</span>
输出结果:
null
323
323