-------------------------------------------------android培训、java培训期待与您交流!----------------------------------
一、概述
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编曲译器挡住源程序中的非法输入,编译器编译带类型 说明的集合时会去除掉“类型”的信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。
List<Integer> list=new ArrayList<Integer>();
//使用反射添加不同类型数据
list.getClass().getMethod("add",Object.class).invoke(list, "abc");
System.out.println(list.get(0));
1.ArrayList<E>类定和ArrayList<Integer>类引用中涉及如下术语:
1)整个称为ArrayList<E>泛型类型
2)ArrayList<E>中的E称为类型变量或类型参数
3)整个ArrayList<Integer>称为类型的类型
4)ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
5)ArrayList<Integer>中的<>念着typeof
6)ArrayList称为原始类型
2.参数化类型与原始类型的兼容性:
1)参数化类型可以引用一个原始类型的对象,编译报告警告,例如,
Collection<String> c=new Vector();//可不可以,不就是编译器一句话
2)原始数型可以引用一个参数化类型的对象,编译报告警告,例如,
Collection c=new Vector<String>();//原来的方法接受一个集合参数,新的类型 也要能传进去
3.参数化类型不考虑类 型参数的继承关系:
1)Vector<String> v=new Vector<Object>();//报错
2)Vector<Object> v=new Vector<String>();//也报错
4.在创建数组实例时,数组的元素不能使用参数的类型,如:
Vector<Integer>[] vectorList=new Vector<Integer>[10];
5.下面的写法不会有问题
Vector v1=new Vector<String>();
Vector<Object> v=v1;
二、泛型中的?通配符
使用?通配符可以引用其他各种参数佛手类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数有关的方法。
public static void main(String[] args) {
List<String> lists=new ArrayList<String>();
lists.add("Em");
lists.add("Gm");
printCollecion(lists);
}
public static void printCollecion(Collection<?> cols)
{
for (Object obj : cols) {
System.out.println(obj);
}
System.out.println(cols.size());
//cols.add("C");//添加用到类型,但?不知道是什么类型,所以这个方法不能用
cols=new HashSet<Date>();
}
//? Extends
List<? extends Number> ls1=new ArrayList<Integer>();
//ls1=new ArrayList<String>();//报错
//? super
//java.util.Date是java.sql.Date的父类
List<? super java.sql.Date> ls2=new ArrayList<java.util.Date>();
//ls2=new ArrayList<String>();//报错
总之:不管是extends还是super本身的类还是可以
三、定义泛方法
1)用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。
2)只有引用类型才能作为泛型方汉的实际参数
3)除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,并且可以用&来指事实上多个边界,如<V extends Serializable&Cloneable> void method(){}
4)普通方法、构造方法和静态方法中都可以使用泛型。编译器也不允许创建类型变量的数组。
5)也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch子句中。
6)在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分,如
public static <K,V> V getValue(K key){return map.get(key);}
public static void main(String[] args) {
String[] strs=swap(new String[] { "Em", "Gm" }, 0, 1);
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
Object o="Em";
String s=autoConvert(o);
System.out.println(s);
o=123;
int i=autoConvert(o);
System.out.println(i);
//<>里的类型要和后面一样,因为<>里的类型可以确定T
copy(new ArrayList<String>(), "Em");
//返回推测
int in=add(3,4);
Number n=add(3.4,2);
Object o2=add("Em",123);
}
private static <T> T[] swap(T[] a,int i,int j) {
T temp=a[i];
a[i]=a[j];
a[j]=temp;
return (T[])a;
}
private static <T> T add(T a,T b)
{
return null;
}
private static <T> T autoConvert(Object obj)
{
return (T)obj;
}
private static <T> void copy(List<T> list,T t)
{
list.add(t);
}
四、泛型类
1.在对泛型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型
2.当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型数。
public class ObjectTest<O>
{
private O obj;
public O getObj()
{
return obj;
}
public void setObj(O obj)
{
this.obj = obj;
}
public static void main(String[] args)
{
ObjectTest<String> ot=new ObjectTest<String>();
ot.setObj("123");
}
}
//通过反射获得泛型的实际类型参数
public static void main(String[] args) throws Exception {
Method applyMethod=GenericParameterType.class.getMethod("applyList",List.class);
//Type是Class的父类 这里是拿到泛化参数的类型
Type[] types=applyMethod.getGenericParameterTypes();
//ParameterizedType是Type子接口,有得到泛型类型的方法
ParameterizedType pType=(ParameterizedType)types[0];
System.out.println(pType.getRawType());//拿到List类型
System.out.println(pType.getActualTypeArguments()[0]);//拿到Date泛型类型
}
public static void applyList(List<Date> v1)
{
}
-------------------------------------------------android培训、java培训期待与您交流!----------------------------------