「数据结构」1.初识泛型

个人主页:Ice_Sugar_7
所属专栏:Java数据结构
欢迎点赞收藏加关注哦!

初识泛型

  • 前言
  • 包装类
    • 装箱&拆箱
  • 泛型
    • 擦除机制
    • 泛型的上界
  • 泛型方法
    • 类型推导

前言

在Java中,泛型常常与数据结构一起使用,用来实现对不同类型的数据的增删查改,它使得数据结构更加通用和灵活,也实现了代码的复用。同时在编译时提供类型检查,避免运行时发生类型错误。而Java中现成的数据结构的源码也涉及到泛型……

泛型的重要性不言而喻,下面一起来了解一下吧!

包装类

Java中基本类型不是继承自Object类,为了让泛型代码可以支持基本类型,Java给每个基本类型都对应了一个包装类型

基本数据类型 包装类
int Integer
char Character
float Float
double Double
boolean Boolean
  • 除了 int 和 char 类型,其他类型的包装类都是基本数据类型首字母大写
  • 包装类属于引用类型

装箱&拆箱

装箱:将基本数据类型转换为对应的包装类对象
拆箱:包装类对象——基本数据类型

int a = 10;
Integer integer = a;  //装箱
System.out.println(integer);  //打印结果是10

我们会发现,这个过程编译器自动将基本数据类型转换为对应的包装类对象,这是自动装箱
我们也可以通过包装类的构造函数valueOf()方法来显式装箱(就是手动装箱)

int a = 10;
Integer integer = new Integer(a);
        
Double d = Double.valueOf(20.0);

// 拆箱操作,将 Integer 对象中的值取出,放到一个基本数据类型中
int c = integer.intValue();

泛型

JDK1.5引入泛型这个语法。通俗来说,泛型就是“适用于多种类型”
泛型的语法如下:

class 泛型类名称<类型形参列表> {
	//这里可以使用类型参数
}

//可以有多个类型形参
class ClassName<T1, T2, ..., Tn> {
	//...
}

你会发现它的语法和定义方法很相似,只不过是现在是以类型作为形参
类名后的 代表占位符,表示当前类是一个泛型类

实现一个类,类中包含一个数组成员,数组可以存放任意类型的数据,也可以根据成员方法返回数组中某个下标的值

public class myArray<T> {
    public Object[] array = new Object[10];

    public void set(int pos,T val) {
        array[pos] = val;
    }

    public T get(int pos) {
        return (T)array[pos];  //把返回的类型强转为指定类型
    }
}

在创建数组对象的时候不能这么写:

public T[] array = new T[10];

注意:不能new泛型类型的数组
为什么呢?这与泛型编译过程中的擦除机制有关

擦除机制

对于刚才上面的代码,我们通过命令javap -c 查看字节码文件
可以看到所有的T都是Object
「数据结构」1.初识泛型_第1张图片

擦除机制指的是:在编译的过程中,将所有的T替换为Object的机制
既然T在编译期间会被换为Object,那为什么还是不能写T呢?因为JVM规定不能这么写,它规定只能new Object类型的数组

所以,以后我们就这么写:

public Object[] array = new Object[10];

泛型的上界

定义泛型类时,有时需要对传入的类型变量进行一定的约束,我们可以通过类型边界来约束:

class 泛型类名称<类型形参 extends 类型边界> {
	//...
}

比如:

public class MyArray<E extends Number> {
	//...
}

这里就限定了E的范围,E只能是Number本身或是Number的子类

还有一种形式,可以限定E一定是实现了某个接口的类:

public class MyArray<E extends Comparable<E>> {
	//...
}

比如上面这个泛型类,E一定是实现了Comparable接口的
下面展示一下这种形式的应用:

写一个泛型类,求一个数组中的最大值

思路分析:要求最大值,就涉及大小比较,而我们知道类是引用类型,要比较大小就需要用到之前讲过的compareTo方法,也就是说要实现Comparable接口

class Alg<T extends Comparable<T>> {
    public T findMaxValue(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}

泛型方法

有可以适用于多种类型的泛型类,那自然也有适合多种类型的泛型方法
语法:

方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }

举个例子:写一个求最大值的泛型方法

public static <T extends Comparable<T>> T findMax(T[] array) {
    T max = array[0];
    for (int i = 1; i < array.length; i++) {
        if(max.compareTo(array[i]) < 0) {
                max = array[i];
        }
    }
    return max;
}

类型推导

类型推导指编译器根据传入的实参的参数类型推导出泛型方法中的类型参数
以刚才的求最大值方法为例:

public static void main(String[] args) {
    Integer[] array = {2,7,1,9,6,5};//数组中的元素自动转换为包装类对象
    int ret = Alg.findMax(array); //由array的类型推导得出T为Integer
    System.out.println(ret);
}

我们也可以自己指定类型参数,不使用类型推导,只需在方法名前面加上<类型参数>就ok了

int ret1 = Alg.<Integer>findMax(array);

你可能感兴趣的:(Java数据结构,数据结构,开发语言,java)