首页 > 代码库 > 黑马程序员-张老师基础5-泛型

黑马程序员-张老师基础5-泛型

泛型:

泛型只是提供给编译器。在编译完之后,生产字节码文件时就擦除类型信息,<>泛型就不在了

泛型的术语:

整个Arraylist<E>:称为泛型类型。

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

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

Arraylist<Integer>中的Integer称为类型参数的实例。

Arraylist<Integer>中的<>是typeof

Arraylist称为原始类型。

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

    --参数化类型可以引用一个原始类型的对象,会警告。例如:

    --Collection<Integer> c = new Vector();

    --Collection c = new Vector<String>();同样警告

参数化类型不考虑类型参数<E>的继承关系。

Vector<String> v = new Vector<Object>();错误,因为V get的元素必须是String的,如果get的是Object的,那泛型有神马用。如果Object不写,可以

Vector<Object> v = new Vector<String>()//难理解,挺难

思考题:下面的代码会报错吗,

Vector v1 = new Vector<Stirng>();

Vector<Object> v = v1;//V1此时仍是原始类型。不报错。编译器只会一行一行的扫描。

?通配符

    Collection<String> coll1= new ArrayList<String>();  

       coll1.add("hahah");

    private static void pringtCollection(Collection<?> coll) {

       // 如何打印<?>中的对象

       //coll.add("abc");//不行,因为要传的参数不确定

       for(Object obj:coll){//不关什么都是object

           System.out.println(obj);

           coll = new HashSet<Date>();//这个可以,==赋值动作。

        // coll.add("String");错误因为,前面是?,类型不确定,不能先定义好类型。但是用反省<T>就可以.

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

    不可以调用与参数有关的方法。

           coll.size();//可以,与参数无关。

       }

    }

<T>与通配符?的区别:<T>在里面可以添加元素等操作。  

private static<T> void pringtCollection(Collection<T> coll,T objt) {

        

       for(Object obj:coll){//不管什么对象都是object

           System.out.println(obj);

        coll = new HashSet<T>();//这个可以,==赋值动作   

        coll.add(objt);//与通配符?的区别

       coll.size();//可以,与参数无关。

       }

    }

 通配符?的扩展

 限定通配符的上边界:

正确:Vector<?extends Number> x = new Vector<Integer>();

错误:Vector<?extends Number> x = new Vector<String>(); 

*限定通配符的下边界:

正确:Vector<?super Integer> x = new Vector<>(Number);

错误:Vector<?super integer> x = new Vector<>(Byte);

*提示:限定通配符总是包括自己。

自定义泛型方法:

用于放置泛型的类型参数的尖括号应出现在方法的返回类型之前。按照惯例,类型参数通常用单个大写字母表示。

*用一个面试题讲:把一个数组中的元素的顺序颠倒一下

       swap(new String[]{"fdf","dfs","fdfdf"},0,1);

//错误  swap(new int[]{2,1,2,5},1,2);//int[]{},不可以是int,必须是引用型。   

    }

    private static<T> void swap(T[] t,int i,int j) {

       // TODO Auto-generated method stub

       T tem = t[i];

       t[i] = t[j];

       t[j]=tem;

    }

泛型的使用只能是引用型类型。不能是基本数据类型。

不仅在使用的时候可以使用extends ,在定义是也可以。如:public <A extends Annotation> A getAnnotation(Class<A> annotationClass)

并且可以使用&来指定多边界,如:<V extends Serializable&cloneable> void method(){}

*普通方法,构造方法,静态方法都可以加泛型。

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

show()<T extends Exception>throws T

{

try

{  

}

catch (Exception e)//这个Exception不可以用T表示。

{

    throw<T>

}}

*<>可以指定多个变量,用逗号隔开。

    Integer[] arr= new   Integer[4];

    Integer[] arr1 = new Integer[5];

    copyArray1(arr1,arr);

//  copyArray1(new Date[10],new Integer[10]);注意这个也可以,它会推断出一个交集

//  copyArray1(new Vecotr<Date>[10],new Integer[10]);这个则不可以。

    private static<T> void copyArray1(T[] dest,T[] orig) {

    // TODO Auto-generated method stub

    for(int x = 0 ;x<orig.length;x++){

       dest[x]=orig[x];

    }   }

 *自定义泛型类

 public class GenericDao<E> {

    public void add(E x){}

    public E findById(int id){

       return null;

    }

    public void delete(E obj){}

    public void update(E obj){}

    public Set<E> findByconditions(String whrer){

       return null;

    }

    Dao:data access object 对象访问数据。

    //public static void show(E e){}静态方法能使用泛型类型的变量,对象的方法,静态不创建对象。静态方法只能自己定义,

如果类中有多个方法要使用泛型,就用类级别。

泛型类:写在类名后面。泛型方法:写在void前面。

泛型类:

    在整个类中有效,如果被方法使用,一旦对象类型明确,所有方法的类型已经明确。

泛型的弊端:创建对象时,类<T>已经明确了类型,而定义方法上的T实际上已经被明确了,只能跟着对象走。那么如果想单独调用方法,传入两一个类型E,此时便受到了限制。想要      更灵活就定义泛型方法。

泛型方法:

    为了让不同方法可以操作不同类型,如<E> void show(E e)和<T> void method(T t),那么就可以将泛型定义在方法上,而且两个方法可以互补影响。

静态泛型方法: 

    静态方法不可以访问类上定义的泛型(如在静态方法中打印类上的泛型<T> t)。这时静态加载,还未加载,报错。此时可以使用静态泛型。

    如果静态方法操作的应用数据类型不明确,可以将泛型定义在方法上。

通过泛型的反射获取一个集合中的具体类型

import java.util.Vector;

public class Demogeneric { 

    public static void main(String[] args) throws Exception {

       // TODO Auto-generated method stub

       Vector<Date> v = new Vector<Date>();

       //如何通过反射获取一个集合中的具体泛型类型

       //因为泛型在编译器之后会被擦出,所以无法通过V的字节码文件来获取泛型的类型。字节码中没有泛型。

       //但是将V传递给方法,并通过获取方法上的参数列表来获取。

       applyVector(v);

       Method applyMethod = new Demogeneric().getClass().getMethod("applyVector", Vector.class);

       Type[] types = applyMethod.getGenericParameterTypes();

       for(Type t:types){          System.out.println(t);//java.util.Vector<java.util.Date>

       }}

    public static void applyVector(Vector<Date> d){

    }}