Java泛型理解与泛型的具体使用

 2022-09-07
原文地址:https://blog.51cto.com/u_208751/5637652

一、泛型定义

泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。泛型也可以看出是一个变量,用来接收数据类型。

以集合类ArrayList源码为例:

    //类定义时,不知道集合中会存储什么类型的参数,所以类型使用泛型
    //E:未知的数据类型 
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    //成员方法get        
    public E get(int index) {}
    //成员方法add
    public boolen add(E e){}

二、泛型使用

以集合类ArrayList创建具体类型时为例:

    //创建集合对象时指定String数据类型
    Collection<String> collection = new ArrayList<>();
    
    /**
    * public boolean add(E e):把给定的对象添加到当前集合中。
    */
    collection.add("Hello");
    collection.add("World");
    collection.add("!!!!!");

三、使用泛型的好处

不使用泛型在程序运行期可能会发生类型转换错误

    public static void main(String[] args) {
            ArrayList arrayList = new ArrayList<>();
            //不使用时泛型时,集合中可以任意加入Object类型
            arrayList.add("Hello");
            arrayList.add(100000);
    
    
            Iterator iterator= arrayList.iterator();
            while(iterator.hasNext()){
                Object object= iterator.next();
                System.out.println(object);
    
                //不使用泛型,在程序运行期进行Object类型强制转换时会发生类型转换错误
                //Exception in thread "main" java.lang.ClassCastException:
                // java.lang.Integer cannot be cast to java.lang.String
                String string =(String)object;  
                System.out.println(string);
            }
        }

使用泛型在代码编译期就可以提示类型错误

    public static void main(String[] args) {
    
            //定义时指定String类型
            ArrayList<String> arrayList = new ArrayList<>();
    
            arrayList.add("Hello");
            //在编译期时就发生错误
            //arrayList.add(100000);
    
            //迭代器根据集合对象的数据类型进行定义
            Iterator<String> iterator= arrayList.iterator();
            while(iterator.hasNext()){
                //使用泛型,由于在定义时就指定了数据类型,不需要进行类型转换
                String string = iterator.next();
                System.out.println(string);
            }
        }

四、定义含有泛型的类

泛型类,是在实例化类的时候指明泛型的具体类型
以下代码为定义含有泛型的类MyGenericClass

    /**
     * @author zhuhuix
     */
    public class MyGenericClass<E> {
    
        private E name;
    
        public E getName() {
            return name;
        }
    
        public void setName(E name) {
            this.name = name;
        }
    
        public static void main(String[] args) {
            //创建MyGenericClass对象,泛型使用String
            MyGenericClass<String> myGenericClass1 = new MyGenericClass<>();
            myGenericClass1.setName("jack");
            System.out.println(myGenericClass1.getName());
    
            //创建MyGenericClass对象,泛型使用Integer
            MyGenericClass<Integer> myGenericClass2 = new MyGenericClass<>();
            myGenericClass2.setName(10000);
            System.out.println(myGenericClass2.getName());
    
        }
    }

五、定义含有泛型的方法

泛型方法,是在调用方法的时候指明泛型的具体类型
以下代码为普通类为定义一个泛型的方法

    /**
     * @author  zhuhuix
     * 定义一个普通类,在普通类中定义泛型方法及调用
     */
    public class MyGenericMethod {
    
        //定义泛型的方法:在public 与void之间有一个泛型T,可以认为此方法为泛型方法
        public <T> void myMethod(T t){
            System.out.println(t);
        }
    
        public static void main(String[] args) {
            MyGenericMethod myGenericMethod = new MyGenericMethod();
            //调用泛型方法时指定泛型参数为String
            myGenericMethod.myMethod("Hello");
            //调用泛型方法时指定泛型参数为Integer
            myGenericMethod.myMethod(10000);
        }
    }

五、定义含有泛型的接口

泛型接口与泛型类的定义及使用相同。

    /**
     * @param <T> 接口中的泛型
     * @author zhuhuix
     */
    public interface MyGenericInterface<T> {
    
        void myGenericIntefaceMethod(T t);
    
    }
    
    //接口中使用泛型,则实现类也必须使用泛型
    public class MyGenericInterfaceImpl<T> implements MyGenericInterface<T> {
    
        @Override
        public void myGenericIntefaceMethod(T t) {
            System.out.println(t);
        }
    
        public static void main(String[] args) {
           //创建MyGenericInterface对象,指定泛型为String
            MyGenericInterface<String> myGenericInterface1= new MyGenericInterfaceImpl<>();
            myGenericInterface1.myGenericIntefaceMethod("Hello World");
    
            //创建MyGenericInterface对象,指定泛型为Integer
            MyGenericInterface<Integer> myGenericInterface2= new MyGenericInterfaceImpl<>();
            myGenericInterface2.myGenericIntefaceMethod(111111);
        }
    }

六、泛型的通配符

1、泛型通配符的常规用法

泛型的通配符用 ? 表示,代表任意的数据类型,不能创建对象使用,只能作为方法的参数使用。也就是说泛型通配符?只能出现在方法的参数中。

    /**
     * @author zhuhuix
     */
    public class MyGenericMatch {
    
        //该成员方法通过迭代器进行遍历ArrayList,
        // 但传入的集合参数为不确定的数据类型,所以用泛型通配符进行定义
        public static void printArray(ArrayList<?> arrayList){
            Iterator<?> iterator = arrayList.iterator();
            while(iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
    
        public static void main(String[] args) {
            ArrayList<String> arrayListString = new ArrayList<>();
            arrayListString.add("Hello");
            arrayListString.add("World");
            arrayListString.add("!!!!!");
    
            ArrayList<Integer> arrayListInteger = new ArrayList<>();
            arrayListInteger.add(1);
            arrayListInteger.add(2);
            arrayListInteger.add(3);
    
            //通配String类型
            printArray(arrayListString);
            //通配Integer类型
            printArray(arrayListInteger);
        }
    }
2、泛型通配符的上限限定与下限限定

上限限定: ? extends E 代表使用的泛型只能是E类型的子类/本身
下限限定: ? super E 代表使用的泛型只能是E类型的父类/本身
也就是说通过上下限的限定,限定方法参数数据类型的范围。

    /**
     * @author zhuhuix
     */
    public class MyGenericMatchLimit {
        
        //泛型上限限定:泛型通配符?必须时Number类型或者Number类型的子类
        public static void printCollection1(Collection<? extends Number> collection){
            Iterator<?> iterator = collection.iterator();
            while (iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
    
        //泛型下限限定:泛型通配符?必须时Number类型或者Number类型的父类
        public static void printCollection2(Collection<? super Number> collection){
            Iterator<?> iterator = collection.iterator();
            while (iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
    
        public static void main(String[] args) {
            Collection<Integer> collection1 = new ArrayList<>();
            Collection<Number> collection2 = new ArrayList<>();
            Collection<Object> collection3 = new ArrayList<>();
            
            //正确
            printCollection1(collection1);
            
            //正确
            printCollection1(collection2);
            
            //报错:Object为Number的父类,超过上限,泛型上限限定只能是Number或Number的子类
            //printCollection1(collection3);
    
            //报错:Integer为Number的子类,超过下限,泛型下限限定只能是Number或Number的父类
            //printCollection2(collection1);
            
            //正确
            printCollection2(collection2);
            
            //正确
            printCollection2(collection3);
            
        }
    }