Android基础篇-Java 泛型

1、什么是泛型

         泛型是jdk5中引入的一个新特性,泛型提供了编译时的类型安全检查机制,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,泛型不存在于Java虚拟机中,java泛型是一个伪泛型。

2、泛型种类

  •  泛型类  

通用的泛型类定义格式如下:

class name

其中T1,T2..是类型参数,类型参数既可以有一个或者有多个。下面使用一个具体的例子来使用泛型类,该类中的泛型参数可以任意指定非基本类型(任何类类型,任何接口类类型,任何数组类型,甚至是另一个类型变量)

/** * Generic version of the Box class.
 * @param  the type of the value being boxed
 */
public class Box { 
   // T stands for "Type"  
    private T t;
    public void set(T t) { 
        this.t = t; 
    }
    
    public T get() { 
        return t; 
    } 
}
  • 泛型方法

 在上面的Box类中有open()是一个泛型方法,注意这get和set这2个方法的类型参数依赖于Box类的类型参数,Box类的类型参数定义什么类型,那么这2个方法的类型参数就是啥,比如new Box(String) 定义的类型参数是String,那么get和set方法中的参数类型就是String,这get和set方法不是泛型方法.只有open()是泛型方法,识别泛型方法很简单就看方法前面有没有 ,有这个就是泛型方法,没有这个就不是。

     /**
     * 普通的方法,原因这个是泛型类在实例化时指定了泛型类的具体类型,他只是一个普通的方法,下面的 
     * get()方法也是同理
     */
    public void setT(T t) {
        this.t = t;
    }

     /**
     * 普通的泛型方法
     */
    public T getT() {
        return t;
    }

     /**
     * 普通的泛型方法
     */
     public  void open(T t){
        
    }

  下面我们实例化一下参数化类型(指定了泛型的类型参数):

  public static void main(String[] args) {
        Box box = new Box<>();
        box.setT("这是一个String类型的类型方法实参");
//       int i = box.getT(); //编译器报错,返回的getT返回类型是String,但是我们用了int类型去接收,编译不通过
        String t = box.getT();
        System.out.println(t);
    }

    打印结果

    

 注意此时的open方法中参数的泛型参数T和 和 Box类的泛型T不是同一个泛型变量,原因在于open方法中指定了一个新的泛型参数T。我们同样使用上面box实例去调用open方法,并且同样的调用set方法做一个对比

Android基础篇-Java 泛型_第1张图片

 

通过编译器的代码提示我们看到,set方法中提示我们传入的参数类型指定的是String,而open方法提示的参数类型还是为指定的类型参数,得出结论,open泛型方法中的类型参数T和Box类中的类型参数不是同一个类型,open类型方法的类型参数根据传入的实参的实际类型来的。而set和get种的T 是参数化类型指定的类型,get和set只是普通的方法,而不是泛型方法。

  • 泛型接口

public interface IBox {
    void pack(T t);
}

3、通配符

      在通用代码中,称为通配符的问号( ? )表示未知类型。通配符可以在多种情况下使用:作为参数,字 段或局部变量的类型;有时作为返回类型(尽管更具体的做法是更好的编程习惯)。通配符从不用作泛 型方法调用,泛型类实例创建或超类型的类型参数。

  • 上界通配符 

       上界通配符就是将未知类型限定为特定类型或者该类型的子类型。上界通配符只能读不能存

       上界通配符使用 ? 后跟extends  关键字,假设你要编写一适用于List 或者List的方法,可以使用上限通配符来实现。

下面看这个Test类中有个static方法process,

     

public class Test {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        for (int i = 0; i <3 ; i++) {
            list.add(i);
        }
        process(list);

    }

    static void process(List list){
        for (int i: list) {
            System.out.println(i);
        }
    }
}

运行结果:

Android基础篇-Java 泛型_第2张图片

       从上面可以看到 process方法里面的参数是使用了上限通配符 ,而我们调用的该方法传入的list的类型参数确是却是Number的子类Integer。上限通配符的作用就是放宽了对变量的限制。

      但是使用了上限通配之后,List只能读不能写如下:

Android基础篇-Java 泛型_第3张图片

  • 下界通配符

        下界通配符就是将位置类型限制为特定类型或者该类型的超类型。下界通配符只能存不能读

        使用方式:? super  特定类型

下面的process_1方法中传递了一个list,使用了下届通配符         

static void process_1(List list){
        for (int i = 0; i <3 ; i++) {
            list.add(new Integer(i));
        }
        System.out.println(list.size());
    }

调用该方法结果:

 看到为list中添加了3个Integer对象,数组的长度为3.,现在读取list中的对象,

Android基础篇-Java 泛型_第4张图片

读取方法报错,由此可见使用了下界通配符的的list只能存不能读。

  • 无界通配符

无界通配符类型使用通配符 来指定,例如List这就是所谓的未知类型的列表,有2种情况下,无界通配符是一种有用的方法。

 1、如果你正在编写一个可以使用object类中国提供的功能和方法。

 2、当代码使用通用类总不依赖于类型参数的方法时。例如list.size,list.clear。

考虑下面的printList方法

public static void printList(List list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
} 
  

printList 的目标是打印任何类型的列表,但是它无法实现这个目标 - 它仅打印一个 Object 实例列表; 它不能打印 List List List  等,因为它们不是 List  的子类型。 要写一个通用的 printList 方法,使用 List

public static void printList(List list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}

因为对于任何具体类型 A,List  是 List  的子类型,所以可以使用 printList 打印任何类型的列表:

List li = Arrays.asList(1, 2, 3);
List  ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);

4、使用泛型的好处

  • 类型安全,编译器在代码开发阶段就能够进行类型的验证

  • 消除强制类型的转换,消除代码种的强制类型转换,代码可读性更高

  • 提高方法的复用性,


你可能感兴趣的:(java;android)