自学内容网 自学内容网

12.Java 泛型(自定义泛型类、自定义泛型接口、自定义泛型方法、泛型的继承与通配符)

一、泛型引入

1、为什么需要泛型

传统方式存在的问题

  1. 不能对加入到集合中的数据类型进行约束

  2. 遍历时,需要进行类型转换

泛型的理解与好处

  1. 编译时能检查添加元素的类型

  2. 能减少类型转换的次数

2、泛型初体验
(1)说明
  • 这里以 Dog 类为例
ArrayList<Dog> list = new ArrayList<Dog>();
  1. 不使用泛型:放入集合时,Dog 类型会先转换为 Object 类型,取出时,需要转换为 Dog 类型

  2. 使用泛型:放入集合和取出时,不需要进行类型转换

(2)演示
package com.my.test;

import java.util.ArrayList;
import java.util.Iterator;

public class GenericTest {
    public static void main(String[] args) {
        ArrayList<Dog> list = new ArrayList<>();
        list.add(new Dog("小黄", 2));
        list.add(new Dog("小汪", 3));
        list.add(new Dog("小多", 4));
        System.out.println("========== 增强 for 循环遍历 ==========");
        for (Dog dog : list) {
            System.out.println(dog);
        }
        System.out.println("========== 迭代器循环遍历 ==========");
        Iterator<Dog> iterator = list.iterator();
        while (iterator.hasNext()) {
            Dog dog = iterator.next();
            System.out.println(dog);
        }
    }
}

class Dog {
    String name;
    int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 输出结果
========== 增强 for 循环遍历 ==========
Dog{name='小黄', age=2}
Dog{name='小汪', age=3}
Dog{name='小多', age=4}
========== 迭代器循环遍历 ==========
Dog{name='小黄', age=2}
Dog{name='小汪', age=3}
Dog{name='小多', age=4}
3、泛型概述
  1. 在类声明或实例化时制定好需要的具体类型

  2. 可以保证在编译时没有警告,运行时就不会产生 ClassCastException(类型转换异常)

  3. 通过标识表示类中某个属性的类型,某个方法的参数类型或返回值类型

4、泛型语法
  1. 自定义泛型类
class 【类名】 <T> {}
  1. 自定义泛型接口
class 【接口名】 <T> {}
  1. 自定泛型方法
【修饰符】 <T> 【返回数据类型】 【方法名】(【参数列表】) {}
5、注意事项
  1. T 表示类型(Type 的缩写,也可以为 K、V 等),且必须是引用类型

  2. 指定泛型具体类型后,可以传入该类型或者其子类类型

  3. 泛型的简写

// 完整写法
ArrayList<Dog> list = new ArrayList<Dog>();
// 简写
ArrayList<Dog> list = new ArrayList<>();
  1. 这样写 ArrayList<> list = new ArrayList<>();,默认指定泛型具体类型为 Object 类型

二、自定义泛型类

1、基本介绍
class 【类名】 <T> {}
2、注意事项
  1. 普通成员可以使用泛型
T t;
  1. 使用泛型的数组不能初始化,因为不能确定 T 的类型,无法开辟空间,在指定泛型的具体类型后才能初始化
// 错误写法
T arr[] = new T[];
  1. 静态成员不能使用泛型,因为静态成员与类相关,类加载时,静态成员无法确定泛型的具体类型,无法完成初始化

  2. 泛型的具体类型在创建对象时确定

  3. 创建对象时,没有指定泛型的具体类型,默认为 Object 类型

3、演示
  • CustomGenericsClassTest.java
package com.my.test;

public class CustomGenericsClassTest {
    public static void main(String[] args) {
        Person<String> person1 = new Person<>("jack");
        Person<Integer> person2 = new Person<>(10);
        person1.show();
        person2.show();
    }
}

class Person<T> {
    T t;

    public Person(T t) {
        this.t = t;
    }

    public void show() {
        System.out.println(this.t);
    }
}
  • 输出结果
jack
10

三、自定义泛型接口

1、基本介绍
class 【接口名】 <T> {}
2、注意事项
  1. 接口中静态成员不能使用泛型

  2. 接口的泛型的具体类型,在继承接口或实现接口时确定

  3. 没有指定泛型的具体类型,默认为 Object 类型

3、演示
  • CustomGenericInterfaceTest.java
package com.my.test;

public class CustomGenericInterfaceTest {
    public static void main(String[] args) {
        new Student().show("jack");
    }
}

class Student implements Person<String> {

    @Override
    public void show(String s) {
        System.out.println(s);
    }
}

interface Person<T> {
    public void show(T t);
}
  • 输出结果
jack

四、自定义泛型方法

1、基本介绍
【修饰符】 <T> 【返回数据类型】 【方法名】(【参数列表】) {}
2、注意事项
  1. 泛型方法可以定义在普通类和泛型类中

  2. 当泛型方法被调用时,泛型的具体类型被确定

  3. public void method(T t) {} 不是泛型方法,而是使用了泛型

3、演示
  • CustomGenericMethodTest.java
package com.my.test;

public class CustomGenericMethodTest {
    public static void main(String[] args) {
        Cat<String> cat = new Cat<>();
        cat.show(10, "tom");
    }
}

class Cat<K> {
    public<T> void show(T t, K k) {
        System.out.println(t.getClass());
        System.out.println(k.getClass());
    }
}
  • 输出结果
class java.lang.Integer
class java.lang.String

五、泛型的继承与通配符

1、基本介绍
  • 泛型不具备继承性
// 错误写法
List<Object> list1 = new ArrayList<String>();
  1. <?>:支持任意类型

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

  3. <? super A>:支持 A 类以及 A 类的父类,规定了泛型的下限

2、演示
  • GenericExtends.java
package com.my.test;

import java.util.ArrayList;
import java.util.List;

public class GenericExtends {
    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<AA> list3 = new ArrayList<>();
        List<BB> list4 = new ArrayList<>();
        List<CC> list5 = new ArrayList<>();

        printList1(list1);
        printList1(list2);
        printList1(list3);
        printList1(list4);
        printList1(list5);

//        printList2(list1); // ×
//        printList2(list2); // ×
        printList2(list3);
        printList2(list4);
        printList2(list5);

        printList3(list1);
//        printList3(list2); // ×
        printList3(list3);
//        printList3(list4); // ×
//        printList3(list5); // ×
    }

    public static void printList1(List<?> list) {
        for (Object o : list) {
            System.out.println(o);
        }
    }

    public static void printList2(List<? extends AA> list) {
        for (Object o : list) {
            System.out.println(o);
        }
    }

    public static void printList3(List<? super AA> list) {
        for (Object o : list) {
            System.out.println(o);
        }
    }
}

class AA {}

class BB extends AA {}

class CC extends BB {}

原文地址:https://blog.csdn.net/weixin_52173250/article/details/144273035

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!