• java泛型


    一,为什么会有泛型

    假设我们想要定一个StringArrayList类:

    public class StringArrayList {
        private String[] array;
        private int size;
        public void add(String e) {...}
        public void remove(int index) {...}
        public String get(int index) {...}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    然后我们又想要定义一个intArrayList类:

    public class IntegerArrayList {
        private Integer[] array;
        private int size;
        public void add(Integer e) {...}
        public void remove(int index) {...}
        public Integer get(int index) {...}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这不就重复书写代码了吗?
    为了复用代码,我们就想着有一个字符来指代这个类型.于是就有了泛型,顾名思义,就是广义上的类型的别称.

    public class ArrayList<T> {
        private T[] array;
        private int size;
        public void add(T e) {...}
        public void remove(int index) {...}
        public T get(int index) {...}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里ArrayList就是说明这是使用泛型定义的类,其中T就是这个类型代号.
    具体使用的时候,把这个T用具体的类型去赋值即可.

    ArrayList<String> list = new ArrayList<>();
    list.add("A");
    list.add("B");
    list.add("C");
    
    • 1
    • 2
    • 3
    • 4

    二,两种泛型

    既然泛型是类型代号,那有一个类型代号,自然也可以有两个类型代号.

    public class Pair<T, K> {
        private T first;
        private K last;
        public Pair(T first, K last) {
            this.first = first;
            this.last = last;
        }
        public T getFirst() { ... }
        public K getLast() { ... }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在使用的时候:

    Pair<String, Integer> p = new Pair<>("test", 123);
    
    • 1

    三,java泛型的实现方式:擦拭法

    擦拭法就是说:虚拟机对泛型其实一无所知,所有的工作都是编译器做的。
    当我们书写这样的泛型代码:

    public class Pair<T> {
        private T first;
        private T last;
        public Pair(T first, T last) {
            this.first = first;
            this.last = last;
        }
        public T getFirst() {
            return first;
        }
        public T getLast() {
            return last;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    而虚拟机根本不知道泛型。这是虚拟机执行的代码:

    public class Pair {
        private Object first;
        private Object last;
        public Pair(Object first, Object last) {
            this.first = first;
            this.last = last;
        }
        public Object getFirst() {
            return first;
        }
        public Object getLast() {
            return last;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这就导致了一些泛型的局限性:

    3.1,不能是基本类型

    例如int,因为实际类型是Object,Object类型无法持有基本类型:

    Pair<int> p = new Pair<>(1, 2); // compile error!
    
    • 1

    3.2,无法取得带泛型的Class

    public class Main {
        public static void main(String[] args) {
            Pair<String> p1 = new Pair<>("Hello", "world");
            Pair<Integer> p2 = new Pair<>(123, 456);
            Class c1 = p1.getClass();
            Class c2 = p2.getClass();
            System.out.println(c1==c2); // true
            System.out.println(c1==Pair.class); // true
    
        }
    }
    
    class Pair<T> {
        private T first;
        private T last;
        public Pair(T first, T last) {
            this.first = first;
            this.last = last;
        }
        public T getFirst() {
            return first;
        }
        public T getLast() {
            return last;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    因为T是Object,我们对Pair和Pair类型获取Class时,获取到的是同一个Class,也就是Pair类的Class。

    换句话说,所有泛型实例,无论T的类型是什么,getClass()返回同一个Class实例,因为编译后它们全部都是Pair。

    3.3,无法判断带泛型的类型

    Pair<Integer> p = new Pair<>(123, 456);
    // Compile error:
    if (p instanceof Pair<String>) {
    }
    
    • 1
    • 2
    • 3
    • 4

    原因和前面一样,并不存在Pair.class,而是只有唯一的Pair.class。

    四,entends字符

    在Java的泛型中,extends关键字用于限定泛型类型参数的上界(Upper Bound),表示该类型参数必须是指定类型或指定类型的子类。这样可以在泛型类或方法中限制传入的类型参数范围,提高代码的类型安全性。

    下面是一个简单的示例,演示了如何在泛型中使用extends关键字:

    // 定义一个泛型类,类型参数必须是Number类或其子类
    class Box<T extends Number> {
        private T value;
    
        public Box(T value) {
            this.value = value;
        }
    
        public T getValue() {
            return value;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            // 实例化一个Box对象,传入Integer类型参数
            Box<Integer> integerBox = new Box<>(10);
            System.out.println("Integer Value: " + integerBox.getValue());
    
            // 编译错误,String不是Number类或其子类
            // Box stringBox = new Box<>("Hello");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在上面的示例中,泛型类Box使用extends Number限定了类型参数T必须是Number类或其子类。因此,可以实例化Box对象,但不能实例化Box对象,因为String不是Number类或其子类。

    五,super字符

    在Java的泛型中,super关键字用于限定泛型类型参数的下界(Lower Bound),表示该类型参数必须是指定类型或指定类型的父类。使用super关键字可以在泛型类或方法中限制传入的类型参数范围,提高代码的灵活性和可复用性。

    下面是一个简单的示例,演示了如何在泛型中使用super关键字:

    // 定义一个泛型类,类型参数必须是Comparable类或其父类
    class Box<T super Comparable<T>> {
        private T value;
    
        public Box(T value) {
            this.value = value;
        }
    
        public T getValue() {
            return value;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            // 实例化一个Box对象,传入Integer类型参数
            Box<Integer> integerBox = new Box<>(10);
            System.out.println("Integer Value: " + integerBox.getValue());
    
            // 实例化一个Box对象,传入String类型参数
            Box<String> stringBox = new Box<>("Hello");
            System.out.println("String Value: " + stringBox.getValue());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    泛型类Box使用super Comparable限定了类型参数T必须是Comparable类或其父类。因此,可以实例化Box和Box对象,因为Integer和String都实现了Comparable接口。

  • 相关阅读:
    尚硅谷大叔培训:揭秘Flink四种执行图——ExecutionGraph和物理执行图
    【逗老师的无线电】宝峰1701刷OpenGD77
    AI视频检索丨历史视频标签化,助力重要事件高效溯源
    java毕业设计校园商铺mybatis+源码+调试部署+系统+数据库+lw
    【Java基础】时间日期类之Date类、SimplDateFormat类、Calendar类及二月天案例
    芯片自动焊接机器人机械系统的设计
    美团后端开发一面(40min)
    Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告
    el-table中加图标文字提示
    网络面试题(基础版-国庆水篇)
  • 原文地址:https://blog.csdn.net/weixin_42349568/article/details/138152281