🎇个人主页: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> {
//...
}
你会发现它的语法和定义方法很相似,只不过是现在是以类型作为形参
类名后的 <T>
代表占位符,表示当前类是一个泛型类
实现一个类,类中包含一个数组成员,数组可以存放任意类型的数据,也可以根据成员方法返回数组中某个下标的值
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
擦除机制
指的是:在编译的过程中,将所有的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);