泛型

泛型是JDK1.5的新特性,类似于C++中的模板,但是仅限于表面。Java中的泛型只是在编译器中实现,用于编译时类型检查,编译后,生成普通的非泛型字节码,这种实现技术成为erasure“擦除”,Java之所以只在编译时实现,是因为若运行时支持泛型,需要拓展虚拟机指令集,工作量庞大,并且使Java厂商升级其JVM造成很大困难。

术语:

1.  ArrayList<E>    泛型类型,其中E称为泛型变量或类型

2.  ArrayList<Integer>参数化得泛型类型,其中Integer称为参数化的类型变量

3.  ArrayList<Integer>   <>念做:typeOf

4.  ArrayList   原始类型


使用泛型之前,定义的集合可以加入任何类型的数据:

      ArrayListlist = new ArrayList();

      list.add("name");

      list.add("123456");

      list.add(100);

  list.add(100L);

当从list中取出时,由于不知道存入的类型,所以每次取出都要进行类型转换:

String name = (String) list.get(0);

或者:

    int age= (Integer) list.get(2);

即使list中所有对象均为String ,取出时仍然需要进行转换,否则会编译错误。

使用泛型后:

ArrayList<String> list = newArrayList<String>();

      list.add("123");

      list.add("abc");

String name =  list.get(0);

       list中只能加入string类型的数据,这样更安全,并且取出时不需要每次进行转换,直接定义为string即可。

在使用泛型对集合的类型进行限制时,例如ArrayList<String>,这时,定义的集合只能加入string类型的数据,加入其它类型数据会编译错误。但是泛型只是在编译时有效,编译通过后,会去掉“类型”信息,也就是说ArrayList<String>和ArrayList<Integer>在编译之后(运行时),是完全一样的ArrayList对象,都没有了类型约束。

这样就可以通过两种方式“绕过”泛型的检测:

1、使用反射技术,可以“绕过”这种约束,向集合中加入其它类型的对象,例如:

ArrayList<Integer> list =new ArrayList<Integer>();

list.add(abc);

直接向list中加入字符串“abc”会编译错误。

如果通过反射调用list的add方法则可以向集合中加入字符串:

list.getClass().getMethod("add",Object.class).invoke(list, "abc");

System.out.println(list.get(0));

就可以成功的向集合中加入字符串,并且可以正常输出。

1、      利用兼容性

ArrayList<Integer> list = new ArrayList< Integer>();

这时,list只能加入Integer类型数据,但是,参数化类型和原始类型是有兼容性的,可以先定义一个基础类型集合:

ArrayList list0 =new ArrayList();

      list0.add("username");

      list0.add(100);

   list0.add(100L);

在用list去引用定义的集合,即:

ArrayList<Integer> list = list0;

list.add(100);       //引用后,可以继续向list中加入数据,但是只能加入Integer类型数据


参数化类型必须一致,引用自己的父类或者父类引用子类均是错误的:

ArrayList<String> list = newArrayList<Object>();

ArrayList<Object> list = newArrayList<String>();


自定义泛型:

注意:

1、只有对象类型如Integer,String,Double,Long,Object等才可以作为泛型的类型参数,基本数据类型不可以作为类型参数,如:int,long,double等不可以。

2、自定义泛型时,类型是自动转换的,自动取最大的或两个都能包括的:

public static <T> T add(T a ,T b){

    return null;

   }

上面这个自定义的泛型方法,若调用:

add(1,1);    则返回Integer

add(1.0,1.2);    Double

add(1.0,1);    Number

add(1,”abc”);   Object

3、自定义泛型时,若参数已经是一个对象,则不会自动转换,并且只能使用对象类型的参数:

public static <T> Tadd(T[] a){     return null;  }

这时,参数本身就是一个对象,若传入参数add(new int[]{});是错误的,int不能作为泛型的类型参数,只能传入add(newString[]{});或者add(new Integer[]{1,2});等对象类型参数。

4、自定义泛型时,还可以使用extends限定符,表示定义的类型限定继承的父类。

public static <T extends Number> Tadd(T[] a){

      return null;

   }

限定了extends Number之后,String等非Number子类就不可以作为类型参数,而Integer,Long,Double等Number子类则可以作为类型参数。

5、多个类型参数

如果方法需要多个参数类型,则可以定义方法时,使用多个参数类型,中间用“,”隔开,例如传入T、X、Y类型的参数:

public static <T,X,Y> voidadd(T t,X x,Y y){

      return null;

   }

6、返回类型的解释

若传入参数中存在类型T,返回T,则代表返回的类型和传入参数的类型一致,例如:

public static <T> voidadd(T t){

      return null;

   }

若返回的类型并没有在参数中存在,则代表需要什么类型,就返回什么类型,比如:

public static <T> void add(Object obj){

     returnnull;

  }

返回:Integer  a = add(1);

        Stringb = add("username");

需要返回Integer时,T就是Integer类型,需要返回String时,T就是String类型。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值