------ android培训、java培训、java基础学习技术总结、期待与您交流! ----------
泛型
体验泛型
jdk 1.5以前的集合类中存在什么问题
ArrayList collection1=new ArrayList();
collection1.add(1);
collection1.add(1L);
collection1.add("abc");
int i=(Integer)collection1.get(1); //编译时强制另外i行转换且运行时出错!
jdk 1.5的集合类希望你在定义集合时,明确表示你要向集合中装哪种类型的数据,无法
加入指定类型意外的数据
ArrayList<String> collection2=new ArrayList();
collection2.add(1); //编译时报告错误
collection2.add(1L); //编译时报告错误
collection2.add("abc");
String str=collection2.get(0);// 不需要再进行强制转换
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的
非法输入,编译器编译带类型说明的集合时会去除"类型"信息,使程序运行效率不受影响,
对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样,就可以往某个泛型集合中
加入其他类型的数据,例如,用反射得到集合,再调用其add方法即可。
了解泛型
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
整个称为ArrayList<E>泛型类型或类型参数
整个ArrayList<Integer>称为参数化的类型
ArrayList<Integer>中的Integer称为类型参数的实例或实际类型的参数
ArrayList<Integer>中的Integer中的称为typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译报告警告,例如,
Collection<String> c=new Vector();
原始类型可以引用一个参数化类型的对象,编译时报告警告,例如:
Collection c=new Vector<String>();
参数化类型不考虑类型参数的继承关系:
Vecor<String> v=new Vector<Object>();//错误;
Vector<Object> v=new Vector<String>(); //也错误
编译器不允许创建类型变量的数组。即在创建数组实例时,数组元素不能使用参数化
的类型,例如,,下面语句有错误:
Vector<Integer> vector[]=new Vector<Integer>[10];
思考题:下面的代码会报错误吗?
Vector v1=new Vector<String>();
Vector<Object> v=v1;
泛型中的?通配符
问题:
定义一个方法,该方法用于打印出任意参数化类型的集合的所有数据,该方法如何定义呢?
错误方式:
public static void printCollection(Collection<Object> cols){
for(Object obj:cols){
System.out.println(obj);
}
cols.add("String");//没错
cols=new HashSet<Date>();//会报告错误!
正确方式:
public static void printCollection(Collection<?> cols){
for(Object obj:cols){
System.out.println(obj);
}
cols.add("String");//错误,因为它不知道未来匹配就一定是String
cols.size();//没错,此方法与参数没有关系
cols=new HashSet<Date>();
总结:
使用?通配符可以引用其他参数化类型,?通配符定义的变量主要用作引用,
可以调用与参数无关的方法,不能调用与参数化有关的方法。
泛型中的?通配符的扩展
限定通配符的上边界:
正确:Vector<? extends Number>x=new Vector<Integer>();
错误:Vector<? extends Number>x=new Vector<String>();
限定通配符的下边界:
正确:Vector<? super Integer> x=new Vector<Number>();
错误:Vector<? super Integer> x=new Vector<Byte>();
提示:
限定通配符总是包括自己
泛型集合的综合
能写出下面的代码即代表掌握了JAVA的泛型集合类:
HashMap<String,Integer> hm=new HashMap<String,Integer>();
hm.put("zxx",19);
hm.put("lis",18);
Set<Map.Entry<String,Integer>> mes=hm.entrySet();
for(Map.Entry<String,Integer> me:mes){
System.out.println(me.getKey()+":"me.getValue());
对在jsp页面中也经常对set或map集合进行迭代:
<c:forEach items="${map}" var=entry">
${entry.key}:${entry.value}
</c:forEach>
由C++的模版函数引入自定义泛型
如下函数的结构很相似,仅类型不同
int add(int x,int y){
return x+y;
}
float add(float x,float y){
return x+y;
}
定义泛型方法
java的泛型方法没有C++模版函数功能强大,java中的如下代码无法通过编译:
<t> T add(T x,T y){
return(T)(x+y);
//return null;
}
交换数组中的两个元素的位置的泛型方法语法定义如下:
static<E> void swap(E[] a,int i,int j){
E t=a[i];
a[i]=a[j];
a[j]=t;
}
用于放置泛型的类型参数的尖括号应该出现在方法的其他所有修饰符之后和在方法的返回类型之前,也
就是紧邻返回值之前。按照惯例,类型参数通常用过单个大写字母表示。
只有应用类型才能作为泛型方法的实际参数,swap(new int[3],3.5);语句会报告编译错误。
除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如,
Class.getAnnotation()方法的定义。并且可以用&指定多个边界,如
<V extends Serialzable&cloneable> void method(){}
普通方法、构造方法和静态方法中都可以使用泛型。编译器也不允许创建类型变量数组。
也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,
但是不能用于catch子句中。
在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分,例如:
public static <K,V> V getValue(K key){
return map.get(key);}
示例1:
public class GenericTest {
public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
// TODO Auto-generated method stub
/* ArrayList collection1=new ArrayList();
collection1.add(1);
collection1.add(1L);
collection1.add("abc");
int i=(Integer)collection1.get(1); */
ArrayList<String> collection2=new ArrayList();
// collection2.add(1);
//collection2.add(1L);
collection2.add("abc");
String str=collection2.get(0);
Constructor constructor1=String.class.getConstructor((StringBuffer.class));
String str2=(String) constructor1.newInstance(new StringBuffer("abc"));// 需要产生同样类型的对象
System.out.println(str2);
ArrayList<Integer> collection3=new ArrayList();
System.out.println(collection3.getClass()==collection2.getClass());
//collection3.add("abc");
collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
System.out.println(collection3.get(0));
printCollection(collection3);
HashMap<String,Integer> maps=new HashMap<String,Integer>();
maps.put("zxx",28);
maps.put("lhm",35);
maps.put("flx",33);
Set<Map.Entry<String,Integer>> entrySet=maps.entrySet();
for(Map.Entry<String,Integer> entry:entrySet){
System.out.println(entry.getKey()+":"+entry.getValue());
}
add(3,5);
Number x1=add(3.5,3);
Object str6=add(3,"abc");
swap(new String[]{"abc","xyz","itcast"},1,2);
//swap(new int[]{1,3,5,4,5),3,4}; 不能是基本类型
}
public static void printCollection(Collection<?> collection){
//collection.add("abc");
System.out.println(collection.size());
for(Object obj:collection){
System.out.println(obj);
}
}
//Class<Number> x=String.class.asSubclass(Number.class);
//Class<?> y;
//Class<String> x;//Class.forName("java.lang.String");
//y=x;
public static <T> void swap(T[] a,int i,int j){
T tmp=a[i];
a[i]=a[j];
a[j]=tmp;
}
private static <T> T add(T x,T y){
return null;
}
}
示例3: