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 类的父类,不限于直接父类,规定了泛型的下限 ​