Java泛型

一.泛型的概述

​ 泛型是java 1.5的新特性,本质是参数化类型,就是将要操作的数据类型指定为一个参数。泛型可以使用在类,接口,方法中,分别叫做泛型类,泛型接口以及泛型方法。

​ 比如ArrayList<String> list = new ArrayList<>()就是一个泛型类。

​ 为什么要使用泛型?

​ 在没有泛型之前,将数据存入集合,是这样子操作的:

public class GenericTest {
    public static void main(String[] args) {
        ArrayList array = new ArrayList();

        array.add("Hello");
        array.add(123);

        String str = (String)array.get(0);
        int num = (int)array.get(1);

        System.out.println(str);
        System.out.println(num);
    }
}

​ 存入数据的时候是可以任意类型,取出来时需要做一个类型转换,这样子操作就存在一个问题,过了许久后可能会忘记了集合的第几个数据是什么类型,一旦搞错,就会产生一个异常java.lang.ClassCastException

​ 引入泛型之后,代码就变成了这样子的:

public class GenericTest {
    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList();

        array.add("Hello");
        // array.add(123);

        String str = array.get(0);
        // int num = (int)array.get(1);

        System.out.println(str);
        // System.out.println(num);
    }
}

​ 在编译时就已经确定了参数类型为String,如果存入集合的数据不是String,在编译时就会报错,在取出数据时也不需要进行类型转换了,这样一来,使得在运行时可能发生的java.lang.ClassCastException异常在编译时期就能被编译器发现,从而从运行时错误变成了编译时期的错误,并且在使用的时候避免了类型转换的麻烦。

二.泛型的定义

  1. 定义泛型类的格式

    修饰符 class 类名<代表泛型的变量> { ... }

    比如源码中的ArrayList的定义是这样的:

    public class ArrayList<E> extends AbstractList<E>
    
    ​    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    
    {
    	....
    }
    

    泛型类的编写比普通类要稍微复杂一些,我们可以根据普通类的编写来进行改造从而完成泛型类的编写。

    比如先创建一个普通类Person

    public class Person {
        private String name;
        
        public Person(String name) {
            this.name = name;
        }
    
        public String getName() {
            return this.name;
        }
    }
    

    然后使用T来标记需要指定的类型,这里是String,改写后的Person类如下:

    public class Person<T> {
        private T name;
        
        public Person(T name) {
            this.name = name;
        }
    
        public T getName() {
            return this.name;
        }
    }
    
  2. 定义泛型方法的格式

    修饰符 <代表泛型的变量> 返回值类型 方法名(参数) { ... }

    比如可以在普通类中定义泛型方法:

    public class Person {
        private String name;
        
        public Person(String name) {
            this.name = name;
        }
    
        public String getName() {
            return this.name;
        }
    
        public <T> void print (T msg) {
            System.out.println(msg.getClass());
        }
    }
    
  3. 定义泛型接口的格式

    修饰符 interface 接口名<代表泛型的变量> { ... }

    比如:

    public interface List<E> {
        ....
    }
    
  4. 泛型类、泛型方法和泛型接口的确定时间

    上面介绍了如何定义泛型,但是这个泛型在什么时候确定泛型类型呢?

    对于泛型类,是在创建对象时候确定泛型类型的,比如:``ArrayList list = new ArrayList<>()`

    对于泛型方法,是在方法被调用的时候确定泛型类型的,比如Person p = new Person(); p.print("hello java");

    对于泛型接口,是有两种情况存在的:

    第一种:在实现接口时候指定泛型类型。

    第二种:如果实现接口的时候仍旧使用了泛型,则在创建接口实现类对象时候指定泛型类型。

  5. 泛型的定义需要注意的几点

    • 泛型的类型只能是引用类型,不可以是基本类型

    • <代表泛型的变量> 尖括号里可以使用任意的字母,对编译器来说都是一样的,但是习惯上使用T,E,K,V等字母来表示(完全是因为程序员习惯)

      其中主要是因为这些字母都代表了一个含义:

      • **T :Type(类型) **
      • E:Element(元素)
      • K:Key(键)
      • V:Value(值)

三.泛型的通配符

​ 泛型有三种类型的通配符:

  • <? extends T>:上边界通配符

    意义:表示只能接受T类型或者T类型的子类型

    缺陷:只能读取对象,不能添加任何对象(null除外)

  • <? super T>:下边界通配符

    意义:表示只能接受T类型或者T类型的父类型

    缺陷:只能添加对象,不能读取对象(Object除外)

  • <?>:无界通配符

    等同于:<? extends Object>

比如有Object类,String类,Number类,Integer类,其中Number类是Integer类的父类

// 泛型的上边界,此时泛型?,必须是Number或者其子类
public static void getElement1(Collection<? extends Number> c) {}
// 泛型的下边界,此时泛型?,必须是Number或者其父类
public static void getElement2(Collection<? super Number> c) {}

public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement1(list1);	
    getElement1(list2);	// error
    getElement1(list3);
    getElement1(list4);	// error
    
    getElement2(list1); // error
    getElement2(list2); // error
    getElement2(list3);
    getElement2(list4);
}
posted @ 2020-01-16 19:56  小毛驴Lucas  阅读(109)  评论(1)    收藏  举报