❶使用泛型的好处
没有使用泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中。使用泛型集合,
可以将一个集合中的元素限定为一个特定类型,集合中只能存储同一种类型的对象,这样更安全;
并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换,这样更方便
❷泛型的作用
只是提供给javac编译器的,编译器可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,
对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,
只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。
比方说下面两个集合去掉参数化之后其二者字节码相同
ArrayList<String> collection2 = new ArrayList<String>();
ArrayList<Integer> collection3 = new ArrayList<Integer>();
System.out.println(collection3.getClass() == collection2.getClass());
通过去参数化之后可以通过反射为其添加各种类型的参数
collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
❸泛型中的?通配符
①可以理解为占位符
使用?通:配符可以引用其他各种参数化的类型,
?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,
不能调用与参数化有关的方法
public static void printCollection(Collection<?> cols)
{
for(Object obj:cols)
{
System.out.println(obj);
}
cols.add("string");//错误这个方法与参数化有关,因为它不知自己未来匹配就一定是String
cols.size();//没错,此方法与类型参数没有关系
cols = new HashSet<Date>();//使用?通配符可以引用其他各种参数化的类型
}
②限定通配符的上边界(?extends E)
正确:Vector<? extends Number> x = new Vector<Integer>();
原因:这个?必须是Number类的子类
错误:Vector<? extends Number> x = new Vector<String>();
原因:不是Number类的子类
③限定通配符的下边界(?super E)
正确:Vector<? super Integer> x = new Vector<Number>();
原因:这个?必须是Integer类的父类或者祖宗类
错误:Vector<? super Integer> x = new Vector<Byte>();
原因:同Integer同级了
❹自定义泛型的运用
①泛型运用在方法上
把一个数组中的元素的顺序颠倒一下
public static <T> void swap(T[] a, int i, int j) {
T t = a[i];
a[i] = a[j];
a[j] = t;
}
②泛型运用在自定义泛型类上
如果不用泛型的方式,一个项目中有很多实体类型和要编写很多Dao,有没有一个更简便的方法呢,那么就使用泛型定义dao类吧
class GenericDAO<T>
{
public void save(T t)
{
}
public void delete(int id)
{
}
public void update(T t)
{
}
public T findById(int id)
{
return null;
}
public Set<T> findByConditions(String conditions)
{
return null;
}测试代码:
GenericDAO<ReflectPoint> dao1 = new GenericDAO<ReflectPoint>();
dao1.save(new ReflectPoint(3,3));
dao1.update(new ReflectPoint(5,3));
GenericDAO<Point> dao2 = new GenericDAO<Point>();
dao2.save(new Point(1,2));
dao2.update(new Point(4,5));
}
这样就使得代码更通用以及更面向对象和扩展性
③通过泛型获取泛型参数里面的实际类型(以后写框架的重点)
通过变量是没有办法知道其泛型实际参数,但是我们可以通过方法获得其参数列表,并且参数列表是以泛型的类型返回,那么就可以获取到泛型里面参数的实际类型
public static void main(String[] args) throws Exception
{
Method applyMethod = Notes.class.getMethod("applyVector", Map.class,List.class);
//得到applyVector方法参数里面的泛型参数列表
Type[] types = applyMethod.getGenericParameterTypes();
//得到参数列表里面的第一个泛型参数
ParameterizedType pType = (ParameterizedType)types[0];
//得到泛型参数类型(这里是Map类型)
System.out.println(pType.getRawType());
//得到泛型参数里面的实际类型(这里有Integer,String)我们获取第一个
System.out.println(pType.getActualTypeArguments()[0]);
}
public static void applyVector(Map<Integer,String> map,List<String> list)
{
}
②泛型里面的例题
定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象
private static <T> void fillArray(T[] a,T obj){
for(int i=0;i<a.length;i++){
a[i] = obj;
}
}
采用自定泛型方法的方式打印出任意参数化类型的集合中的所有内容
public static void printCollection(Collection<?> collection){
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
public static <T> void printCollection2(Collection<T> collection){
//collection.add(1);这种方式可以调用集合里的add方法
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
定义一个方法,把任意参数类型的集合中的数据安全地复制到相应类型的数组中 public static <T> void copy1(Collection<T> dest,T[] src){
}
定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的另一个数组中
public static <T> void copy2(T[] dest,T[] src){
}
----------------------------------------- android培训、java培训、java学习型技术博客、期待与您交流! --------------------------
详情请查看:http://edu.csdn.net/heima