当前位置: 首页 > article >正文

【数据结构】(3)包装类和泛型

一、包装类

1、什么是包装类

        将基础类型包装成的类就是包装类。由于基础类型不是继承 Object 类的类,所以在泛型不能直接支持基础类型,为了解决这个问题,就需要把基础类型转换为对应的包装类

基础类型对应的包装类
基础类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

2、装箱和拆箱

装箱:基础类型转换为包装类。

拆箱:包装类转换为基础类型。

以下为过时的写法

3、自动装箱和拆箱

        我们现在用的都是自动装箱、拆箱,第一种方式是最好的。

        用 javap -v 命令反汇编字节码文件,可以看到编译器会自动添加 valueOf (装箱)和 intValue(拆箱) 方法。

4、包装类的常量缓冲池

        同是比较有相同内容的对象的地址,结果却不同:

        这是因为 Integer 有一个常量池机制,当加载 Integer 类时,就会自动把 -128 ~ 127 范围的对象(常用的数值)放到常量池中:

        因此,i8、i9 引用都是存放的常量池中 127 对象的地址,而 i10、i11 引用分别存放不同的堆中新创建的对象的地址:

:128 并没有超过 Integer 的取值范围,它的范围大概是 -21亿 ~ 21 亿。

包装类的缓冲值范围
包装类缓冲值范围
Byte-128 ~ 127
Short-128 ~ 127
Integer-128 ~ 127
Long-128 ~ 127
Float
Double
Character0 ~ 127
Booleantrue 和 false

二、泛型

1、什么是泛型

        一般的类和方法只能固定接收、返回一种类型的数据,但有时我们希望接收、返回很多种类型的数据。比如写一个加法器,里面的数据可以是整型、浮点型,如果使用方法重载,方法里的步骤相同,只是数据类型不同,造成代码的冗余。使用泛型可以解决这个问题,相当于将数据类型参数化,可以给同一个类或方法灵活地指定任意类型

2、使用 Object 类

        如果我们需要实现一个数组类,这个类中的数组成员可以存放任意类型的元素,并且有 set、get 指定位置的元素的方法。可以使用 Object 类,因为它是任意类的父亲,通过任意类型向上转型为 Object 类实现:

 

        但是这种方法有个缺点,一是获取值时需要手动强制类型转换;二是无法确定一种类型,即让类或方法在使用时持有一种类型,而不是同时拥有任意类型。而泛型不需要手动强制类型转换,并且在创建对象时就将某一种类型作为参数传入,指定其类型编译器对其进行类型检查。既能让类指定不同的类型,又能给对象指定一种类型。

3、泛型的使用

        将上面的类改写成泛型:

  •  <T> 表示该类为泛型类,类型形参常用的名称有:

  • MyArray 中仍用 Object[] 类型创建对象,因为 T 只是泛型类的标志,它并没有实际的构造函数

  • 在定义引用时,已确定为 String 类, 因此 new 对象时可根据上下文推导类型省略为 <>
  • 优点:编译器自动进行类型转换、类型检查;一份代码支持多种类型。

4、裸类型

        泛型参数不指定,默认 T 为 Object,它只是为了兼容老版本,不建议使用:

        我们学习泛型,重点不在定义泛型类,而在泛型类的实例化,后续使用 java 中的集合类时,会经常用到泛型的实例化

5、如何编译泛型——擦除机制

        编译器先将泛型类型擦除,再替换为 Object 或边界类型。set 中把指定类型转为 Object (向上转型),get 中强制转换 Object 为指定类型(针对泛型类)。

        最后针对子类重写泛型父类的方法,避免没有真正覆盖父类方法,编译器会自动生成桥接方法。

擦除前:

public class Node<T> {
    T data;
    public void setData(T data) {
        this.data = data;
    }
}
public class StringNode extends Node<String> {
    @Override
    public void setData(String data) {
        super.setData(data);
    }
}

擦除后:

public class Node {
    Object data;
    public void setData(Object data) {
        this.data = data;
    }
}

public class StringNode extends Node {
    // 形参中,子类的 String 与父类替换后的 Object 不一致
    // 未成功覆盖
    @Override
    public void setData(String data) { 
        super.setData(data);
    }
}

自动生成桥接方法:

public class StringNode extends Node {
    // 子类与父类的方法签名一致
    @Override
    public void setData(Object data) {
        setData((String) data);
    }
}

6、泛型上界

        对泛型的类型范围的上界进行约束

        在实现计算器时,使用泛型上界,可以限制类型为数字。若没有 extends,默认为 extends Object。

7、泛型方法

        将泛型写到方法名后,返回值类型前,让返回值类型、参数列表都能使用该泛型

        泛型方法的使用,类型推导见上文 “泛型的使用” :

8、通配符

        使泛型类引用能接收所有类型的泛型类对象:

三、总结

        泛型的重点在泛型类对象怎么实例化,为后续集合类的使用做铺垫。而怎么定义泛型类、怎么定义泛型方法、擦除机制、泛型上界、通配符等相比较下就不那么重要了。


http://www.kler.cn/a/529112.html

相关文章:

  • 如何实现一个CLI命令行功能 | python 小知识
  • 想品客老师的第天:类
  • pytorch生成对抗网络
  • cpp实战项目—string类的模拟实现
  • 本地部署DeepSeek开源多模态大模型Janus-Pro-7B实操
  • go-zero学习笔记(一)
  • 关于DNN检测中替换caff用Tensorflow的注意事项
  • 7.攻防世界fileclude
  • Qt Creator 中使用 vcpkg
  • Doki Doki Mods Maker小指南
  • 网络原理(3)—— 传输层详解
  • RK3568连接wifi(connmanctl工具)
  • 使用 Docker 部署 pSQL 服务器 的教程
  • 如何为用户设置密码
  • 爬取豆瓣书籍数据
  • 本地部署DeepSeek教程(Mac版本)
  • 一个数如果恰好等于他的因子之和,这是就成为“完数“,例如6=1+2+3.编程找出1000以内的所有完数
  • 2025.2.1(迭代器,auto,for遍历)
  • PID算法的数学实现和参数确定方法
  • 新集成,Sui 的 Phantom 时代正式开启!
  • Java小白入门教程:数组(一维数组)
  • kamailio-ACC_RADIUS模块详解,附加AAA协议
  • 一文读懂Python之random模块(31)
  • C++:虚函数与多态性习题2
  • 洛谷 P1734 最大约数和 C语言
  • 讯飞绘镜(ai生成视频)技术浅析(三):自然语言处理(NLP)