Skip to content

泛型


泛型的引出

java
public class pra {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("java");
        arrayList.add("jack");
        arrayList.add("jom");

        arrayList.add(new a());

        for (Object obj :arrayList) {
            String str = (String)obj;
            System.out.println(str);
        }
    }
}

class a{
    public a() {
    }
}

由于添加了 a 对象,但是在遍历的时候遍历的是字符串对象,这个时候就会抛出 ClassCastException 异常

问题分析

(1)不能对加入到集合 ArrayList 中的数据类型进行约束(不安全

(2)遍历的时候需要进行数据类型转换,如果集合的数据量大,对显效率有影响

泛型优势

由于集合中添加的对象,当集合中的对象不为同一类对象时,遍历集合就会出现异常,这个时候可以通过泛型来约束集合存储的对象类型

基本介绍

(1)泛型又称参数化类型,是 Jdk5.0 出现的新特性,解决数据类型的安全性问题

(2)在类声明或实例化时,需要指定好需要的具体的类型

(3)Java 泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException 异常。同时,代码更加简洁、健壮

(4)泛型的作用:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法返回值的类型,或者是参数类型

(5)泛型的理解:是一种表示数据类型的数据类型

(6)泛型的优点

1. 编译时,检查添加元素的类型,提高了安全性

2. 减少了类型转换的次数,提高效率

3. 不再提示编译警告

泛型的使用

基本语法

T、K、V 不代表值(可以替换成其他任意字母),而是表示一种数据类型

单例集合

java
ArrayList<T> arrylist = new ArrayList<T>()

双例集合

java
HashMap<K,V> arrylist = new HashMap<K,V>()

⭐ 推荐写法

java
ArrayList<String> arrylist = new ArrayList<>()

应用场景

类中可以有多个泛型变量

java
class <K,T....>{

}

接口

java
interface 接口名<T>{

}

使用细节

(1)泛型变量只能是引用类型

错误案例:List<int> list = new ArrayList<int>()

(2)如果不写泛型默认是 Object 类型,下方的两条语句等价

java
ArrayList list = new ArrayList();

ArrayList<Object> list = new ArrayList<>()

(3)泛型指定具体类型后,可以传入该类型或者其子类型

java
public class pra {
    public static void main(String[] args) {
        animal<a> a = new animal<a>(new a());
        animal<a> b = new animal<a>(new b());
    }
}

class a{

}

class b extends a{

}

class animal<T>{
    T e;

    // 构造器
    public animal(T e){
        this.e = e;
    }

    public void getclass(){
        System.out.println(e.getClass());
    }
}

代码分析

指定了 animal 类只能存储 a 类对象,但是 b 类是 a 的子类,即 animal 类既可以是 a 对象也可以是 b 对象

代码示例

java
public class pra {
    public static void main(String[] args) {
        HashMap<String,student> hashMap = new HashMap<>();
        hashMap.put("18",new student("jackson"));
        hashMap.put("20",new student("jack"));
        hashMap.put("23",new student("jom"));

        // 先取出entryset
        Set<Map.Entry<String, student>> entries = hashMap.entrySet();

        // 构建迭代器(指向单例集合)
        Iterator<Map.Entry<String, student>> iterator = entries.iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, student> next = iterator.next();
            System.out.println("key:" + next.getKey() + " value:" + next.getValue());
        }
    }
}

class student{
    String name;

    public student(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                '}';
    }
}

自定义泛型类

基本介绍

(1) 普通成员可以使用泛型(属性、方法)

(2) 使用泛型的数组,不能初始化(由于不知道数组的类型,无法在内存开辟空间)

(3) 静态方法中不能使用泛型

因为静态是和类相关的,在类加载时,对象还没有创建

如果静态方法和静态属性使用了泛型,JVM 就无法完成初始化

(4) 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)

(5) 如果在创建对象时,没有指定类型,默认为 Object

(6)泛型是标识符,需要大写

类结构

java
class a<T,K,V...>{
    T age;
    K name;
    V phone_number;
    ...
}

自定义泛型接口

基本介绍

(1) 接口中,静态成员也不能使用泛型

(2)在继承接口或者实现接口时确定泛型接口的类型

(3)如果没有指定类型,默认为 Object

(4)如果一个类实现了泛型接口,则类中实现接口的方法需要需要指定接口方法中的泛型类型

可能是返回值类型或者是方法参数类型使用了泛型

代码示例

java
public class pra {
    public static void main(String[] args) {

    }
}

interface a<T,R>{
    // 接口中的变量默认是静态的,需要赋初值

    void hi(T t,R r);

    void pay(T t,R r);

    void run(T t,R r);
}

class b implements a<String,Double>{
    @Override
    public void hi(String s, Double aDouble) {

    }

    @Override
    public void pay(String s, Double aDouble) {

    }

    @Override
    public void run(String s, Double aDouble) {

    }
}

代码分析

通过指定泛型的类型来实现接口中的方法

自定义泛型方法

java
public T hi(V a, K b){
    // 方法体
}

(1)泛型方法可定义在普通类或泛型类中,实体信息为泛型方法的定义位置相关内容

(2)泛型方法在调用时确定类型(通过传入的参数自动判断是什么类型)

(3)若修饰符后无 <T,R...> ,像 public void eat(E e) { } 不是泛型方法,只是方法参数使用了泛型

泛型的继承和通配符

(1)泛型不具备继承性

错误案例:List<Object> list = new ArrayList<String>()

(2) < ? > : 支持任意泛型类型

(3) < ? extends A > : 支持 A 类以及 A 类的子类,规定了泛型的上限

(4) < ? super A > : 支持 A 类以及 A 类的父类,不限于直接父类,规定了泛型的下限