Java泛型

1.为什么使用泛型

比如:一个集合不指定类型你实际是想添加String类型,但是一不小心加了一个Integer类型进去,假如这时需要遍历取出所有数据,取出来的值你都赋给了一个string类型的变量,遍历到那个Integer数据时,程序会抛出ClassCastException的异常,这是运行时异常,如使用了泛型可以在编译器,在你添加那个Integer数据时就报错告诉你类型不对不可以往里面添加,可以让问题早点发现。
所以泛型的好处就是安全性和增加代码的可阅读性,还可以增加代码灵活性

// 泛型可以让代码更灵活
    public void testSort() {
        Integer[] arrayInt = new Integer[10];
        sort(arrayInt);

        Double[] doubles = new Double[10];
        sort(doubles);

        Object[] objects = new Object[10];
        sort(objects);
    }

    public void sort(int[] array){}
    public void sort(double[] array){}
    // 使用泛型上面两个方法就可以不需要了
    public <T> void sort(T[] array){}

Java泛型是jdk5新引入的特性,为了向下兼容,虚拟机其实是不支持泛型,所以Java实现的是伪泛型机制,也就是说Java在编译期擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码,所有的泛型类型最终都是一种原始类型,在Java运行时根本就不存在泛型信息

2.泛型方法、泛型类、泛型接口
  • 泛型方法
public <T> AiPlate<T> getAiPlate() {
        return new AiPlate<T>();
    }
    // 注意泛型方法的定义,要在返回值和修饰符中间加一个尖括号
  • 泛型类
public class AiPlate<T> implements Plate<T> {

        @Override
        public void set(T t) {

        }

        @Override
        public T get() {
            return null;
        }
    }
  • 泛型接口
public interface Plate<T> {
        public void set(T t);
        public T get();
    }
3.泛型继承、泛型推断、通配符
  • 泛型继承
// 定义类A1继承AiPlate类,AiPlate类不能跟类型型参
public class A1 extends AiPlate<T> {

    }   
    
// 如果想从AiPlate类派生一个子类,则可以改为如下代码 
// 使用AiPlate类时为T形参传入String类型    
public class A2 extends AiPlate<String> {

    }
  • 泛型推断
class MyUtil<E> {
    public static <Z> MyUtil<Z> nil() {
        return null;
    }

    public static <Z> MyUtil<Z> cons(Z head, MyUtil<Z> tail) {
        return null;
    }

    E head() {
        return null;
    }
}

class Test {

    public static void main(String[] args) {
        
        // 通过方法赋值的目标参数来推断类型参数为String
        MyUtil<String> ls = MyUtil.nil();

        // 无须使用下面语句在调用nil()方法时指定类型参数的类型
        MyUtil<String> mu = MyUtil.<String>nil();

        // 可调用cons()方法所需的参数类型来推断类型参数为Integer
        MyUtil.cons(42, MyUtil.nil());
        
        // 无须使用下面语句在调用nil()方法时指定类型参数的类型
        MyUtil.cons(42, MyUtil.<Integer>nil());
    }
}
  • 通配符

    • 类型

      ?: 表示不确定的Java类型

      T(type)表示具体的一个java类型

      K V (key value)分别代表java键值对中的Key Value

      E(element) 代表Element

4.泛型的类型消除、泛型约束
  • 类型消除
public void testClass() {
        ArrayList<Integer> integers = new ArrayList<>();
        ArrayList<String> strings = new ArrayList<>();

        System.out.println(integers.getClass() == strings.getClass());
    }

    // 通过运行发现两者是相等的,由此可见运行时类信息是完全一致的,泛型被擦除了只留下原始类型,
    // 这里也就是arrayList

    // 如果泛型类型没有限制,会直接擦除成object

    public class AIPlate<T extends Comparable<T>> implements Plate<T> {

        @Override
        public void set(T t) {

        }

        @Override
        public T get() {
            return null;
        }
    }

    // 如果有限制,AIPlate<T extends Comparable<T>> 像这样,字节码中会把T参数泛型擦除成第一个限制类型Comparable,
    // 字节码中有桥方法指向实现的Plate.set方法,将set方法的泛型擦数成object
    // 注意:虽然泛型被擦除了,其实在类的常量池里面保留了泛型信息
  • 泛型约束
    • 无界通配符 <?>

    • 上界通配符 <? extends E>

      static class A{}
      static class A1{}
      static interface B{}
      static interface B1{}
      
      // ok,继承多个类型时应该列出所有类型,并且有类型为类的必须写在接口的前面不然会有报错
      static class C<T extends A & B & B1> {}
      
      // 报错,因为Java是单继承
      static class C1<T extends A & A1 & B & B1> {} 
      
    • 下界通配符 <? super E>

    • ?和T的区别

      ?和T都表示不确定的类型,区别在于T可以进行操作,但是?不可以例如:

      T t = user; //可以

      ?u = user; //不可以

      T是一个确定的类型,通常用于泛型类和泛型方法的定义,?是一个不确定的类型,通常用于泛型的调用代码和形参,不能用于定义类和泛型方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值