现在的位置: 首页 > 综合 > 正文

java笔记 泛型

2017年11月08日 ⁄ 综合 ⁄ 共 3615字 ⁄ 字号 评论关闭

泛型、Type:jdk1.5新增特性

泛型:泛型是提供给javac编译器用的,使其挡住源程序中的非法输入,但一经编译后会去掉类型信息,所以可以通过反射添加其他类型的数据。
ArrayList<T> T为类型参数变量,且实际参数只能是引用类型,<>可以读作"typeof"
ArrayList<String> String为实际类型参数
ArrayList称为原始类型
Vector<?>可以匹配任意类型
Vector<? extends Number> 可以匹配Number类或Number类的子类类型
Vectro<? super Integer> 可以匹配Integer类或Integer的父类类型
public <K,V> V function(K p1, V p2){} 多个类型参数
public <T extends I1 & I2> function(T p){} 即参数p是实现了接口I1和I2的T类型
兼容性:Collection<String> c=new Vector();//ok,but warrning
Collection c= new Vector<String>();//ok,but warrning
参数化类型不考虑类型参数的继承关系:
Vector<String> v=new Vector<Object>();//error!!!
Vector<Object> v=new Vector<String>();//error!!!
Vector v1=new Vector<String>();//ok
Vector<Object> v=v1;//ok,编译器只是单行核对语法,无法捕捉运行时产生的错误。
创建数组实例时,数组元素不能使用参数化类型,如下:
Vector<String>[] vectorArray=new Vector<String>[10];//error!!!

泛型方法中类型参数的类型推断是根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:
a.当某个类型变量只在整个参数列表中或返回值中的一处被应用了,则根据调用方法时该处的实际应用类型来确定其实际类型,如:swap(new String[3],3,4) -> static <E> void swap(E[] a, int i, int j)
b.当某个类型变量在在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型都对应同一种类型来确定,如:add(3,5) -> static <T> add(T a, T b)
c.当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法是这多处的实际应用类型对应到了不同的类型,且没有使用返回值,此时取多个参数中的最大交集类型,如:fill(new Integer[3], 3,5f) -> static void fill(T[]a, T v) 实际对应Numbe类型
d.当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这些多处的实际应用类型对应到了不同的类型,且使用了返回值,这时候优先考虑返回值的类型,如:int x=(3,3.5f) -> static <T> T add(T a, T b) 实际对应类型为Integer,编译错误,将x变量的类型改为Number则通过。
e.参数类型的类型推断具有传递性,下面第一种情况推断实际的参数类型为Object,编译通过,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,则编译错误:
copy(new Integer[5], new String[5]) -> static <T> void copy(T[] a, T[] b);
copy(new Vector<String>(), new Integer[5]) -> static <T> void copy(Collection<T> a, T[] b);

CRUD指对数据库的添/删/改/查。
类的静态方法不能使用限定类级别的泛型类型,只能使用方法级别的泛型
//普遍使用的数据访问类,应用了泛型
public class GenericDao<T>{//类级别的泛型,限定了该类的非静态方法都是针对同一数据类型进行操作
public void save(T obj){}
public void delete(T obj){}
public void delete(int id){}
public void update(T obj){}
public T find(int id){ return null;}
public T find(String name){return null;}
public Set<T> findByConditions(String condition){return null;}
public static <E> void update(E obj){}//方法级别的泛型,静态方法为类所有,不必实例化就可调用,而使用类级别泛型如果不实例化就不知道参数的类型,所以类的静态方法只能使用方法级别的泛型
}
类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,如:
GenericDao<String> dao = null;
new GenericDao<String>();
注意:在对泛型类型进行参数化是,类型参数的实例必须是引用类型,不能是基本类型;当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类共享的,所以静态成员不应该有类级别的类型参数。

public class C{
public static void func(Vector<String> v){}
public static void func(Vector<Date> v){}
//以上2个方法非重载,编译错误
}

通过反射得到方法中的参数泛型的实际类型参数:
需要借助于Method类提供的getGenericParameterTypes()
方法获得类型变量的实际参数化类型。
该方法以Type对象的数组的形式(Type类是Class类的父类),按声明顺序,返回被(调用这个getGenericParameterTypes方法的)Method对象(一段字节码)描述的一个方法的(所有)形式参数的数据类型。如果一个形式参数的类型是参数化的类型(如Vector<String>),则Type对象一定为这个形式参数准确地返回,在源代码中使用的类型参数的实际类型。
假设getGenericParameterTypes()返回的Type对象的数组为Type[] types,则types[0]为第一个形参的数据类型,types[1]为第二个形参的数据类型,依次类推。疑问:是否有一个方法可以检查types的元素是不是一个参数化的类型?
假设types[0]是一个参数化的(parameterized)形参类型,则可以将其转换为ParameterizedType类型,即:ParameterizedType parameterizedType = (ParameterizedType) types[0] 。用parameterizedType对象调用(其所属类ParameterizedType提供的)getActualTypeArguments()就可得到这个参数化类型的实际的类型参数的数组。为什么会是实际的类型参数的数组,因为实际的类型参数可能有多个,如HashMap<K,V>,假如它参数化后是HashMap<String,Object>,则返回的Type数组就有两个元素,索引0位置是String,索引1位置是Object。
实例:
public class C{
public static void applyHashMap(HashMap<String,Object> hm){}
public static void main(String[] args)
{
Method methodApplyHashMap = C.class.getMethod("applyHashMap", HashMap.class);
//得到方法applyHashMap()所有的形式参数的类型
Type[] types[] = methodApplyHashMap.getGenericParameterTypes();
//转换为ParameterizedType类型,不知可不可以先检查types[]的元素是不是ParameterizedType类型
if(types[0].getClass == ParameterizedType.class){

ParameterizedType parameterizedType = (ParameterizedType)types[0];
for(Type typeArg : parameterizedType.getActuralArguments())
{System.out.println(typeArg);}
}
}
}

抱歉!评论已关闭.