Java泛型机制和应用

总结

  • 泛型解决了参数类型缺少检查造成的问题。
  • 泛型可以在类、接口、函数上使用。
  • 通配符是为了让Java泛型支持范围限定,这样使得泛型的灵活性提升,同时也让通用性设计有了更多的空间。

概述

编译期是指把源码交给编译器编译成计算机可执行文件的过程。运行期是指把编译后的文件交给计算机执行,直到程序结束。在Java中就是把.java文件编译成.class文件,再把编译后的文件交给JVM加载执行。

泛型又叫“参数化类型”。泛型就是在定义类、接口、方法的时候指定某一种特定类型(碗),让类、接口、方法的使用者来决定具体用哪一种类型的参数(盛的东西)。Java的泛型是在1.5引入的,只在编译期做泛型检查,运行期泛型就会消失,我们把这称为“泛型擦除”,最终类型都会变成 Object

泛型主要解决的问题:

  • 集合对元素类型没有任何限制引发的业务问题。
  • 把对象写入集合,在获取对象的时候进行强制类型转换出现问题。

语法规则

使用菱形语法表示泛型,例如 List<String> strList= new ArrayList<>();

泛型允许在定义类、接口、方法时使用类型参数,这个类型形参将在变量声明、创建对象、调用方法时动态得指定。

泛型类

类上定义泛型,作用于类的成员变量与函数,代码实例如下:


public class Apple<T> {
    // 使用T类型形参定义实际变量
    private T info;

    public T getInfo() {
        return info;
    }

    public void setInfo(T info) {
        this.info = info;
    }

    public Apple(T info) {
        this.info = info;
    }
    public static void main(String[] args) {
        // 创建变量时候指定泛型类型,构造器只能使用对应类型
        Apple<String> a1 = new Apple<>("苹果");
        System.out.printf(a1.getInfo());
        Apple<Double> a2 = new Apple<>(2.13);
        System.out.printf(a2.getInfo()+"");
    }
}

泛型接口

接口上定义泛型,作用于函数,代码实例如下:

public interface GenericInterface<T> {
    public T get();
    public void set(T t);
    public T delete(T t);
    default T defaultFunction(T t){
        return t;
    }
}

泛型函数

函数返回类型旁加上泛型,作用于函数,代码实例如下:

public class GenericFunction {
    public <T> void function(T t) {
    }
    public <T> T functionTwo(T t) {
        return t;
    }
    public <T> String functionThree(T t) {
        return "";
    }
}

通配符

通配符是为了让Java泛型支持范围限定,这样使得泛型的灵活性提升,同时也让通用性设计有了更多的空间。

  • <?>:无界通配符,即类型不确定,任意类型
  • <? extends T>:上边界通配符,即?是继承自T的任意子类型,遵守只读不写
  • <? super T>:下边界通配符,即?T的任意父类型,遵守只写不读

通配符限定的范围是体现在确认“参数化类型”的时候,而不是“参数化类型”填充后

    /**
     * 1.创建泛型为Number的List类,Integer、Double、Long等都是Number的子类
     *   new ArrayList<>() 等价于 new ArrayList<Number>()
     */
    List<Number> numberList = new ArrayList<Number>();
    
    /**
     * 2.添加不同子类
     */
    numberList.add(1);//添加Integer类型
    numberList.add(0.5);//添加Double类型
    numberList.add(10000L);//添加Long类型
    
    /**
     * 3.创建泛型为Number的List类,Integer、Double、Long等都是Number的子类
     *   引用是泛型类别是Number,但具体实现指定的泛型是Integer
     */
    List<Number> numberListTwo = new ArrayList<Integer>();//err 异常编译不通过
    
    /**
     * 4.创建泛型为Integer的List类,把该对象的引用地址指向泛型为Number的List
     */
    List<Integer> integerList = new ArrayList<Integer>();
    List<Number> numberListThree = integerList;//err 异常编译不通过

上边界通配符只读不写,下边界通配符只写不读。

  • <? extends T>上边界通配符不作为函数入参,只作为函数返回类型,比如List<? extends T>的使用add函数会编译不通过,get函数则没问题。
  • <? super T>下边界通配符不作为函数返回类型,只作为函数入参,比如List<? super T>的add函数正常调用,get函数也没问题,但只会返回Object。

设计原则可以参考 PECS (producer-extends,consumer-super)原则。PECS原则也就是说,如果参数化类型表示一个生产者E,就使用<? extends E>,如果参数化类型表示一个消费者E,则使用<? super E>。

public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值