泛型

《Java编程的逻辑》笔记

概念和原理

  • 泛型:泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入。如下

    • 泛型类:T表示类型参数。
    public class Pair<T>{
        T first;
        T second;
        public Pair(T first,T second){
            this.first = first;
            this.second = second;
        }
        public T getFirst(){
            return first;
        }
        public T getSecond(){
            return second;
        }
    }
    复制代码
    • 泛型方法

      一个方法是不是泛型的,与它所在的类是不是泛型没有是什么关系。

      public static <T> int indexoOf(T[] arr,T elm){
          for(int i=0;i<arr.length;i++){
              if(arr[i].equale(elm)){
                  return i;
              }
          }
          return -1;
      }
      // 泛型参数可以是多个
      public static <U,V> Pair<U,V> makePair(U first,V second){
          Pair<U,V> pair = new Pair<>(first,second);
          return pair;
      }
      // 泛型方法调用时一般不需要特意指定类型参数的实际类型
      makePair(1,"老马");
      复制代码
    • 泛型接口

      // 泛型接口
      public interface Comparable<T> {
          public int compareTo(T o);
      }
      // 实现
      public final class Integer extends Number implements Comparable<Integer>{
          public int compareTo(Integer anotherInteger){
              return compare(this.value,anotherInteger.value);
          }
      }
      复制代码
  • 基本原理:Java泛型是通过擦除实现的,类定义中的类型参数如T会被替换为Object,在程序运行过程中,不知道泛型的实际类型参数,比如Pair,运行中只知道Pair,而不知道Integer。

  • 泛型的好处

    • 更好的安全性
    • 更好的可读性

类型参数的限定

  • 限定上界:现在我们知道Java把类型参数,当做Object,但Java支持限定这个参数的上界。参数必须为给定的上界类型或其子类型,这个限定是通过extends关键字类表示的。这个上界可以是某个具体的类或某个具体接口,也可以是其他类型参数。

  • 上界为具体类:

    public class NumberPair<U extends Number,V extends Number> extends Pair<U,V>{
        public NumberPair(U first,V second){
            super(first,second);
        }
    }
    //调用
    NumberPair<Integer,Double> pair = new NumberPair<>(10,12.34);
    复制代码
  • 上界为某个接口:

    // T表示一种数据类型,必须实现Comparable接口,且必须可以与相同类型的元素进行比较
    public static <T extends Comparable<T>> T max(T[] arr){
        T max = arr[0];
        for(int i=1;i<arr.length;i++){
            if(arr[i].compareTo(max)>0){
                max = arr[i];
            }
        }
        return max;
    }
    复制代码
  • 上界为其他类型参数:

    //E是DynamicArray的类型参数,T是addAll的类型参数,T的上界限定为E
    public <T extends E> void addAll(DynamicArray<T> c){
        for(int i= 0;i<c.length;i++){
            add(c.get(i));
        }
    }
    
    DynamicArray<Number> numbers = new DynamicArray<>();
    DynamicArray<Integer> ints = new DynamicArray<>();
    ints.add(100);
    ints.add(43);
    numbers.addAll(ints);
    复制代码

解析通配符

  • 通配符: <? extends E>
  • 无限定通配符:, DynamicArray<?> 这种限制:只能读,不能写
  • 超类型通配符:<? super E>
  • 通配符比较:
    • 它们的目的都是为了使方法接口更为灵活,可以接受更为广泛的类型。
    • <? super E> 用于灵活写入或比较,使得对象可以写入父类型的容器,使得父类型的比较方法可以应用于子类型对象,它不能被类型参数形式替代。
    • <?>和<? extends E> 用于灵活的读取,使得方法可以读取E或E的任意子类型的容器对象,它们可以用类型参数形式替代,但通配符形式更为简洁。

细节和局限性

  • 使用泛型类、方法和接口 注意点:
    • 基本类型不能用于实例化类型参数
    • 运行时类型信息不适用于泛型
    • 类型擦除可能会引发一些冲突
  • 定义泛型类,方法和接口 注意点:
    • 不能通过类型参数创建对象
    • 泛型类类型参数不能用于静态变量和方法
    • 了解多个类型限定的语法
  • 泛型与数组
    • 不能创建泛型数组
    • Java不支持泛型数组
    • 如果需要存放反省对象,可以使用原始类型的数组,或者使用泛型容器
    • 泛型容器内部使用Object数组,如果要转换泛型容器为对应类型的数组,需要使用反射。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值