------- android培训、java培训、期待与您交流! ----------
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add
方法即可。
泛型的基本定义以及应用,以集合为例子
没有使用泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中。使用泛型集合,可以将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全;并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换,这样更方便。
ArrayList collection1 = new ArrayList(); //集合里可以添加Object对象,什么类型都可以
collection1.add(1);
collection1.add(1L);
collection1.add("abc");
//int i = (Integer)collection1.get(1);
ArrayList<String> collection2 = new ArrayList<String>(); //但是加了泛型的话就不行了, 所添加的类型会被限定
//collection2.add(1); //int类型 ERR
//collection2.add(1L); //LONG类型 ERR
collection2.add("abc");
String element = collection2.get(0);
//且看再一个例子
List list = new ArrayList();
list.add("111");
list.add("222");
Iterator it = list.iterator();
while(it.hasNext()){
String next = (String)it.next(); // 如果没有泛型, 迭代器返回的是一个Object类型..如果是要使用String类型的话,需要强转
System.out.println(next);
List<String> list1 = new ArrayList<String>();
list1.add("111");
list1.add("222");
Iterator<String> it2 = list1.iterator();
while(it2.hasNext()){
String next2 = it2.next(); // 加了泛型, 迭代器就知道它返回的是一个String类型,无需强转
System.out.println(next2);
通过反射类来调用泛型,跳过编译器
由于泛型只是提供给编译器看的,编译完了以后泛型就会被去掉了,所以,只需跳过编译器,不让编译器知道泛型的类型,通过反射的方式就可以自由添加了类型了。(这个叫去类型化)
ArrayList<Integer> collection3 = new ArrayList<Integer>();
ArrayList<Integer> collection2 = new ArrayList<Integer>();
System.out.println(collection3.getClass() == collection2.getClass()); //结果是true
collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
//一定是要Object.class,因为他们的父类是Object, 父类引向子类, 自然就不会报错了..
//而且这个方法现在就是跳过了编译器, 不是由编译器去判断泛型, 而是由编译器自己去调用add方法, 因为编译器处理的是去掉泛型后的二进制代码以确保其他方法的正常运行,所以, getClass方法,跟原始类型是一样的.. 因此, 可以调用而被报错
泛型的通配符
目标: 打印任意一个带有泛型的方法
public static void printCollection(Collection<?> collection){ // ?表示通配符
//collection.add(1); 用了通配符以后不能调用与参数有关的方法
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
泛型的上限与下限
泛型可以限定多个类型
Map<Integer,String> map = new HashMap<Integer,String>();
由于Map没有迭代器, 所以只好将Map转成set 集合;
Set<Map.Entry<Integer,String>> s = map.entrySet();
自定义泛型的应用
private static <T> T add(T x,T y){ //传进来的T是任意的类型, 如果T x和T y 是不同类型, 那么取2个类型的交集
如果使用T当作类型, 那么在方法的返回值前必须加上<T>
return null;
}
add(3,5); //3和5的交集是int
Number x1 = add(3.5,3); // double类型和int 类型的交集是Number
Object x2 = add(3,"abc"); //int 和String 交集是Object
交换数组里的两个元素的位置, 任意类型的数组
private static <T> void swap(T[] a,int i,int j){
T tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
swap(new String[]{"abc","xyz","itcast"},1,2); //交换数组
//swap(new int[]{1,3,5,4,5},3,4); 泛型的类型只能是引用类型, 不是是基本类型, int是基本类型, 所以报错
自定义泛型的综合应用, 类似于Struts和Spring整合的框架
public class GenericDao<E> { //对象里的泛型,说明等下这个类里只能用传进来的<E>这个类型
public void add(E x){ //增, 添加一个对象
}
public E findById(int id){ //查, 根据ID查出这个对象, 一般是单条,也有可能是多条,返回有可能是集合
return null;
}
public void delete(E obj){ //删, 删除整个对象
}
public void delete(int id){// 删, 根据ID删对象
}
public void update(E obj){ //改, 修改这个对象,还少了一个ID, 应该是根据ID来修改这个对象, 这个设计不合适
}
public static <E> void update2(E obj){ //注意: 类里面的静态方法不能使用类的泛型, 泛型是针对对象的实例化的,
//静态方法不用实例化对象都能调用,所以 静态方法如果要使用泛型, 那就单独在返回值前加一个<E>, 这样是表示
//这个方法会单独调用一个泛型, 跟类不一样, 凡是在类方法的返回值前出现的泛型对象, 都跟本类的泛型对象无关
}
public E findByUserName(String name){ //查, 根据姓名查数据, 老师其实说的有点错误, 如果2个用户,他们的密码都一样,
//姓名也一样, 此时就不能那样做了,所以应该是查帐号的唯一性, 而不是名字的唯一性,不然就乱套了
return null;
}
public Set<E> findByConditions(String where){ //查, 就是上面说的,查处多条返回给一个集合
return null;
}
}
通过反射获取到参数里的泛型
Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class); //获取方法,这个前面有介绍过了
// JDK1.5版本的新特性, 在Method里提供了一个获取到参数泛型的一个方法
Type[] types = applyMethod.getGenericParameterTypes(); //返回是一个Type, Class的父类之一..
//我们要想知道获取到的类型,就需要使用到Type子类ParameterizedType;
ParameterizedType pType = (ParameterizedType)types[0]; //由于我们知道方法只有一个Vector参数,所以直接下标[0]
System.out.println(pType.getRawType()); //获取到原始类型, java.util.Vector
//获取到实际的类型参数, 说白了就是已经获取到了泛型.. 这个泛型返回的是Type数组
System.out.println(pType.getActualTypeArguments()[0]); //直接下标[0], 答案就是 java.util.Dota
public static void applyVector(Vector<Date> v1){
}
------- android培训、java培训、期待与您交流! ----------