• Java随笔-泛型


    概述

    泛型,即“参数化类型”,就是将类型由原来的具体类型改成类似于方法中变量参数那样,在使用的时候再传入具体的类型。这种在使用时候将操作的数据类型作为参数,常用在类,方法,接口中。

    使用

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    
    • 1
    • 2

    泛型在容器中使用的最为频繁。

       List<String> listId = new ArrayList<>();
       List<Integer> skuidList = new ArrayList<>();
    
    • 1
    • 2

    泛型的主要目的之一就是指定容器需要存储数据的类型。容器可以持有多种类型的对象,在使用的时候通常一个容器只会存储一种类型的对象,所以泛型在容器中使用最频繁。
    通常为了更好的扩展,又有所约束,会在公共的一些工具或基类中使用泛型,好处如下:

    1. 多种数据类型可以执行相同的代码。
    2. 无需强制类型转换。
    public class GenericTest2<K,V,E> {
        private K key;
        private V value;
        private E other;
    
        public GenericTest2(K key, V value, E other) {
            this.key = key;
            this.value = value;
            this.other = other;
        }
    
        public void show(){
            System.out.println("键:" + key + ",值:" + value + "," + other + "是多余的");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用继承可以实现长度更多的数据类型。

    public class GenericTest3<A,B,C,D> extends GenericTest2<A,B,C> {
        private D d;
        
        public GenericTest3(A key, B value, C other,D d) {
            super(key, value, other);
            this.d = d;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    方法

        public <T> T genericMethod(T t) {
            return t;
        }
    
    • 1
    • 2
    • 3

    泛型方法就是在调用的时候指定具体类型,泛型方法可以在普通类中使用,也可以在泛型类中使用。在泛型类中使用是,如果使用了泛型类声明的类型,此时泛型方法就是不同的方法而不是泛型方法。

    public class GenericTest<T> {
        private T data;
    
        public T getData() {
            return data;
        }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时返回的是泛型类中声明的类型,而不是方法自己声明的类型。
    泛型方法的在修饰符与返回类型之间的类型是必不可少的,只有声明的这个,才能表示这是一个泛型方法。
    在这里插入图片描述
    泛型方法也可以有多个泛型。

      public <K,V> void genericMethod2(K k) {
      }
    
    • 1
    • 2

    接口

    public interface Generator<T> {
    
        void show(T t);
    }
    
    • 1
    • 2
    • 3
    • 4

    实现类:

    public class GeneratorImpl<T> implements Generator<T>{
        @Override
        public void show(T t) {
            System.out.println("泛型:" + t);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    要点

    限定泛型类型。

        /**
         * 取大值
         * @param a
         * @param b
         * @param 
         * @return
         */
        public static <T extends Comparable> T max(T a, T b) {
            return a.compareTo(b) > 0 ? a : b;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果传入的参数没有实现Comparable,则编译报错。限定可以是多个。

        public static <T extends Comparable & Serializable> T max(T a, T b) {
            return a.compareTo(b) > 0 ? a : b;
        }
    
    • 1
    • 2
    • 3

    这里的Comparable & Serializable都是接口,如果是类的话就需要放在第一个位置。

    public class GenericClass {
    }
    
    • 1
    • 2
        public static <T extends GenericClass & Comparable & Serializable> T max(T a, T b) {
            return a.compareTo(b) > 0 ? a : b;
        }
    
    • 1
    • 2
    • 3

    实用类的时候只能使用一个,而且必须放在限定列表的第一个。Java中类只能单继承,而接口是可以多实现的。

    通配符。

    在这里插入图片描述

    • ? extends X,表示参数类型必须是X的子类。
        public static void main(String[] args) {
    
            GenericTest<Father> father = new GenericTest<>();
            GenericTest<Son> son = new GenericTest<>();
            print(son);
        }
    
        static void print(GenericTest<? extends Father> father){
            System.out.println(father);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用? extends X时可以访问X和X的子类,但是不能set方法,因为set的时候编译器不知道具体的数据类型会报错,但是可以是用get方法,get之前类型已确定,也不能卸任非null的数据。

    • ? super X,表示参数类型必须是X的父类。
      在这里插入图片描述
    • 如果没有限制,使用通配符没有意义。
    ArrayList<?> list1 = new ArrayList<>();
    
    • 1

    约束不能使用基本数据类型。

      ArrayList list = new ArrayList<int>();
    
    • 1

    这行代码编译器会报异常:

    Type argument cannot be of primitive type
    
    • 1

    此时使用包装类就没事。

      ArrayList list = new ArrayList<Integer>();
    
    • 1
    • 类型判断只能使用原始类型,不能使用泛型。
      在这里插入图片描述

      在这里插入图片描述
      即使指定了泛型中的类型,也是没有办法判断的,编译器会直接报错的。

    静态域中泛型失效。

    静态域中肯定不能使用泛型,静态域是随着类的加载而加载,而泛型是创建对象的时候才确定,加载静态域的时候对象还没创建呢,所以使用泛型无效。
    在这里插入图片描述

    • 不能创建泛型类数组对象。
      在这里插入图片描述
      但是只声明是可以的。
     GenericTest<String>[] strArray;
    
    • 1

    但是声明完后不能使用,声明没有意义,浪费空间。

    不能捕获泛型类实例。

    在这里插入图片描述
    在这里插入图片描述
    但是catch Throwable或Exception肯定就没问题。

       public <E extends Throwable> void test(E e){
            try {
    
            } catch (Throwable e1){
    
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    泛型中使用父类和子类创建的对象之间没有任何关系。

    父类:

    public class Father {
    }
    
    
    • 1
    • 2
    • 3

    子类:

    public class Son extends Father {
    }
    
    • 1
    • 2

    泛型:
    在这里插入图片描述
    但是对泛型类是可以扩展的。
    扩展:

    public class GenericTest01<T> extends GenericTest<T> {
    }
    
    • 1
    • 2

    使用:

     GenericTest<Father> father = new GenericTest01<>();
    
    • 1

    就像ArrayList。

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    
    • 1
    • 2
    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
    • 1

    Java中泛型是伪泛型。

    Java中泛型在编译后类型会自动擦除类型,是伪泛型,并非真正的泛型,编译后会进行替换和强制转型。所以:

            ArrayList<Integer> list  = new ArrayList<>();
            ArrayList<String> list0  = new ArrayList<>();
            
    
    • 1
    • 2
    • 3

    编译后是一样的。

  • 相关阅读:
    JVM面试常考的4个问题详解
    用python实现在卷积神经网络中,如何计算各层感受野的大小
    阿里云优惠券(代金券)免费领取方法及使用教程分享
    人工智能:神经细胞模型到神经网络模型
    C语言之自定义类型_结构体篇(2)
    terraform简单的开始-vpc cvm创建
    【校招VIP】产品项目分析之系统策划
    Cefsharp开发中遇到的问题
    客快物流大数据项目(九十):ClickHouse的引擎介绍和深入日志引擎讲解
    前端刷题记录
  • 原文地址:https://blog.csdn.net/qq_34202054/article/details/126584974