黑马程序员——Java高新技术之泛型

来源:互联网 发布:金融网络销售工资 编辑:程序博客网 时间:2024/06/06 20:15

-------android培训、java培训、期待与您交流! ----------

泛型

泛型<>:JDK1.5出现的安全机制

泛型好处:

将运行时期的问题ClassCastException(类型转换异常)转移到了编译时期

避免了强制转换的麻烦

什么时候用泛型:

当操作的引用数据类型不确定的时候,就用到了泛型,,其实泛型就是一个用于接收引用数据类型的参数范围

在程序中只要用到了带有<>(泛型)的类或者接口,就要明确传入的具体数据类型

package Generic;import java.util.ArrayList;public class Demo {public static void main(String[] args) {ArrayList<String> al = new ArrayList<String>();al.add("23");al.add("Hello");String s = al.get(1);System.out.println(s);}}
泛型技术是给编译器使用的技术,用于编译时期,限定了输入的类型,确保了类型的安全

泛型的擦除:

编译时,会将泛型去掉,生成的class文件中是不带有泛型的,称为泛型的擦除

擦除原因:

为了兼容运行的类的加载器

泛型的补偿:

获取元素时避免了转换动作,不用强制转换了,称为补偿

package Generic;import java.util.ArrayList;public class Demo {public static void main(String[] args) {ArrayList<String> al = new ArrayList<String>();ArrayList<Integer> al1 = new ArrayList<Integer>();//字节码文件不带有泛型,所以他们相等了System.out.println(al.getClass()==al1.getClass());//true//用反射来添加元素collection2.getClass().getMethod("add", Object.class).invoke(collection2,"abc");System.out.println(collection2.get(0));//abc,所以泛型只是给编译器使用的}}

ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:

整个称为ArrayList<E>泛型类型

ArrayList<E>中的E称为类型变量或类型参数

整个ArrayList<Integer>称为参数化的类型

ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数

ArrayList<Integer>中的<>念着typeof比如这个就叫做ArrayList  typeof  Integer

ArrayList称为原始类型

参数化类型与原始类型的兼容性:

参数化类型可以引用一个原始类型的对象,编译报告警告,但不是异常。例如, Collection<String> c = new Vector();

原始类型可以引用一个参数化类型的对象,编译报告警告,但不是异常。例如, Collection c = new Vector<String>();

参数化类型不考虑类型参数的继承关系:

Vector<String> v = new Vector<Object>(); //错误!

Vector<Object> v = new Vector<String>(); //错误!

编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型

例如,下面语句有错误:

Vector<Integer> vectorList[] = new Vector<Integer>[10];

泛型中的?通配符

使用通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。

泛型的限定:

上限:Vector<? extends Number> x = new Vector<Integer>();

下限:Vector<? super Integer> x = new Vector<Number>();

限定通配符总是包括自己。

只能用作引用,不能用它去给其他变量赋值,只能通过强制类型转换方式来赋值。

package Generic;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;public class GenericDemo {public static void main(String[] args) {Collection<String> c = new ArrayList<String>();println(c);//限定Collection<? super Integer> collection = new ArrayList<Number>();//只能通过强制类型转换方式来赋值。Collection<Number> coll = (Collection<Number>) collection;}private static void println(Collection<?> c) {//调用与参数化无关的方法System.out.println(c.size());//可以引用其他各种参数化的类型c=new HashSet<Integer>();}}
自定义泛型:在方法上,放在返回值前面

/*对于任意一个数组,改变两个元素的位置*/package Generic;import java.util.Arrays;public class GenericMethod {public static void main(String[]args){String [] str = new String[]{"abc","xyz","123"};System.out.println(Arrays.asList(str));swap(str,0,1);System.out.println(Arrays.asList(str));}public static <T> void swap(T[] t,int i,int j){for(int x=0;x<t.length;x++){T temp =t[i];t[i]=t[j];t[j]=temp;}}}
在自定义泛型时:

只有引用类型才能作为泛型方法的实际参数

也可用extends限定符(上限),并可以使用&来指定多个边界

普通方法、构造方法和静态方法中都可以使用泛型。

也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch子句中。

在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分

private static <T extends Exception> sayHello() throws T
{
try{
 
}catch(Exception e){
   throw (T)e;
}
}

如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,在类名后加上泛型参数即可

注意:

在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
静态方法的泛型只能定义在方法上

public class GenericDao<E> {

public void add(E e){

}
public static <E> void staMe(E e){

}

}
类型参数的类型推断

当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用类型来确定,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型

当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型都对应同一种类型来确定

当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候取多个参数中的最大交集类型。

当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型, 并且使用返回值,这时候优先考虑返回值的类型,

参数类型的类型推断具有传递性

通过反射获得泛型的参数化类型

package Generic;import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.Date;import java.util.Vector;public class GenericReflect {public static void main(String[] args) throws Exception {//获取方法Method method = GenericReflect.class.getMethod("add", Vector.class);//获取方法形参类型Type[] type = method.getGenericParameterTypes();//获取参数化类型ParameterizedType pt = (ParameterizedType)type[0];//获取返回值类型System.out.println(pt.getOwnerType());//null//返回参数类型System.out.println(pt.getRawType());//class java.util.Vector//获取实际参数类型System.out.println(pt.getActualTypeArguments()[0]);//class java.util.Date}public static <T> T add(Vector<Date> v){return null;}}

0 0
原创粉丝点击