zoukankan      html  css  js  c++  java
  • thinking in java笔记 15 泛型

    ***概述
       泛型实现了参数化类型的概念,使代码可以应用于多种类型。泛型的最初目的是为了使类或方法具有最广泛的表达能力,这点可以通过解耦类或方法与所使用的类型之间的约束来实现。在创建参数化类型的一个实例时,编译器为你负责转型操作,并且保证类型的正确性。

    ***简单泛型
       许多原因促使泛型的出现,最显著的一个是为了创造容器类。有时,需要能同时持有多个对象。但通常只会使用容器来存储一种类型的对象。泛型的主要目的之一就是指定容器要持有的对象类型,有编译器来保证类型的正确性。

    ***元组
       一次方法调用就能返回多个对象,经常会需要类似的功能。解决办法是创建一个对象,用它来持有想要返回的多个对象。元组是将一组对象直接打包存储与其中的一个单一对象,这个容器对象内元素是只读的。

    ***泛型接口
       泛型可以用于接口,和类使用方法相同。java的泛型局限:基本类型无法作为类型参数。 

    ***泛型方法
       是否拥有泛型方法,与其所在的类是否为泛型没有关系。泛型方法使得该方法能够独立于类而产生变化。应该尽量使用泛型方法而不是泛型类,这样更容易明白。
       定义泛型方法,只需将泛型参数列表置于返回值之前:
        <T> void kk(T t){
                System. out .println(t);
          }
       使用泛型类时,必须在创建对象时指定类型参数的值,而泛型方法则不用指定,编译器会找出具体类型(类型参数推断)。使用泛型方法时和使用普通方法一样,如果调用kk()时传入基本类型,自动打包机制就会介入,将基本类型的值包装为对应的对象。泛型方法和自动打包机制避免了以前我们不得不写的代码。类型推断只对赋值操作有效,其他时候并不起作用。
       在泛型方法中,可以显式地指明类型。 f.<Person>getPerson()

    ***类型信息丢失
       在泛型代码内部,无法获得任何有关泛型参数类型的信息。java泛型是使用擦除来实现的,在使用泛型时,任何具体的类型信息都被擦除,仅知道正在使用一个对象。List<String>和List<Integer>在运行时事实上是相同的类型。
       只有当你希望使用的类型参数比某个具体类型(以及它的所有子类型)更加泛化时(希望代码能够跨多个类工作),使用泛型才有所帮助。

    ***创建数组
       在泛型中创建数组,推荐使用Array.newInstance()方式。
       不能创建泛型数组,解决方案是使用ArrayList.将继续获得数组的行为,以及由泛型提供的编译期的类型安全。成功创建泛型数组的唯一方式是创建一个被擦除类型的新数组,然后对其转型。因为有了擦除,数组的运行时类型就只能是Object[]。
       为了弥补擦除,可以在构造器中传递一个类型标记,以便从擦除中恢复,使得我们可以创建需要的实际类型的数组。转型中产生的警告必须用@Suppress Warnings来压制住,一旦获得了实际类型,就可以返回它,并获得想要的结果,如下:
      
       public class GenericArrayWithTypeToken<T> {
    private T[] array;
    @SuppressWarnings("unchecked")
    public GenericArrayWithTypeToken(Class<T> type, int sz) {
    array = (T[])Array.newInstance(type, sz);
    }
    public void put( int index, T item) {
    array[index] = item;
    }
    public T get( int index) { return array[index]; }
    // Expose the underlying representation:
    public T[] rep() { return array; }
    public static void main(String[] args) {
    GenericArrayWithTypeToken<Integer> gai =
    new GenericArrayWithTypeToken<Integer>(
    Integer. class , 10);
    // This now works:
    Integer[] ia = gai.rep();
    }
    }

    Number[] numbers = new Integer[3];
    numbers[0] = new Integer(0);
    numbers[1] = new Integer(1);
    numbers[2] = new Integer(2);

    numbers[1] = new Double(3.4); //能通过编译,但运行时会报ArrayStoreException


    ***边界
       可以用于在泛型的参数类型上设置限制条件,以强制规定泛型可以应用的类型,更重要的效果是你可以按照自己的边界类型来调用方法。因为擦除移除了类型信息,所以,可以用无界泛型参数调用的方法只是那些可以用Object调用的方法,但如果能将这个参数限制为某个类型子集,就可以用这些类型子集来调用方法。java泛型因此重用了extends关键字。

    ***通配符
           class Fruit {}
    class Apple extends Fruit {}
    class Jonathan extends Apple {}
    class Orange extends Fruit {}

    List<Fruit> fruit= new ArrayList<Apple>();//报错,不能把一个涉及Apple的泛型赋给一个涉及Fruit的泛型
    List<? extends Fruit> fruit= new ArrayList<Apple>();
    用通配符后,List<? extends Fruit>代表具有任何从Fruit机场的类型的列表。用这个List只能调用Fruit的方法。


    ***无界通配符
       <?> 声明:想要Java的泛型来编写这段代码。并非是使用原生类型,但在此处,泛型参数可以持有任何类型。
       当处理多个参数时,又是允许一个参数可以是任何类型,同时为其他参数确定某种特定类型。
       使用确切类型替代通配符类型的好处是:可以用泛型参数来做更多的事,但使用通配符使得必须接受范围更宽的参数化类型作为参数。
       
    ***问题
       1 任何基本类型都不能作为类型参数
          可使用基本类型的包装器类和自动包装机制(自动包装机制不能应用于数组)。当考虑性能时,可使用专门适配基本类型的容器版本。            
  • 相关阅读:
    WINCE创建快捷方式
    Android初级开发第四讲系统中一些属性的区别
    Android初级开发第六讲Activity的布局
    Android初级开发第三讲项目中控件的学习
    物联网产业链及市场分
    读《浪潮之巅》有感
    Hello China V1.75成功运行于Lenovo超级本上
    Android初级开发第七讲特效和数据传递处理
    Android中级第二讲制作搜索页面,使用TextWatcher
    电信运营商物联网实践建议
  • 原文地址:https://www.cnblogs.com/myparamita/p/2203984.html
Copyright © 2011-2022 走看看