八分钟“手撕”包装类与泛型

news2025/1/19 20:31:44

目录

一、包装类

基本数据类型和对应的包装类

装箱和拆箱

【思考题】 

二、泛型

什么是泛型 

引出泛型

怎么定义泛型和使用泛型

裸类型(Raw Type)

擦除机制

额外,注意下列代码: 

泛型的上界

泛型的接口应用 

泛型方法 


一、包装类

简单来说:为了服务泛型,把基本类型做成一个引用类型。

基本数据类型和对应的包装类

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

总结:除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。

装箱和拆箱

public class Type {
    public static void main(String[] args) {
        int i=10;
        double d=1.0;
        //显式装箱
        Integer i1=Integer.valueOf(i);
        Double d1=Double.valueOf(d);
        //隐式装箱
        Integer i2=i;
        Double d2=d;

        //显式拆箱
        int i3=i1.intValue();
        double d3=d2.doubleValue();
        //隐式拆箱
        int i4=i1;
        double d4=d1;

        System.out.println(i1);
        System.out.println(d1);
    }
}
//执行结果
10
1.0

从上面代码中,可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制 也就是自动(隐式) 装 / 拆箱 

小小的思考: 

对于Integer来说,这是个类(引用类型),为什么能直接打印值呢?而不是地址呢?

答:在Integer源码里面,它自己实现了重写toString()方法,可以直接输出值。

【思考题】 

public static void main(String[] args) {
    Integer a = 127;
    Integer b = 127;
    Integer c = 128;
    Integer d = 128;
    System.out.println(a == b);
    System.out.println(c == d);
}
//执行结果
true
false

为什么两次打印会不一样呢? 

答:在Integer这个包装类中,Integer可以允许的值是-128~127如果输入的值在这个区间以内,就直接返回区间的值;也就是说128超出了这个范围,这时候会new一个新的Integer出来,那让我们看看下面源码是怎么写的:

所以说上述的思考题中,128超出了这个区间,new出的两个空间,这时候他们的地址都是不一样的,==比较的是地址,所以返回false。

二、泛型

什么是泛型 

泛型是在JDK1.5引入的新的语法,通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化

引出泛型

实现一个类:

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

思路:

1. 我们以前学过的数组,只能存放指定类型的元素,

例如:int[] array = new int[10]; String[] strs = new String[10];

2. 所有类的父类,默认为Object类。数组是否可以创建为Object?

代码如下:

class MyArray{
    Object[] array=new Object[10];

    public Object getPos(int pos){
        return this.array[pos];
    }
    public void setPos(int pos,Object x){
        this.array[pos]=x;
    }
}
public class Test {
    public static void main(String[] args) {
        MyArray myArray=new MyArray();
        myArray.setPos(0,10);
        myArray.setPos(1,2);
        myArray.setPos(2,"hello");
        String s1=myArray.getPos(2);//编译报错
        String s2=(String)myArray.getPos(2);//需要强转
    }
}
//执行结果
java: 不兼容的类型: java.lang.Object无法转换为java.lang.String

这时我们会有两个问题:

1.这个数组中又有String又有int是不是太混乱了;

2.强转可行,那每次我都需要强转是不是太麻烦了

我期望的是:

你能接收我指定类型的数据,传什么你能放什么,还可以直接使用。

你上面的代码实现的只是:

Object不能把类型作为参数传递,它只是能接收任何类型的数据,毕竟不管是什么类型,都需要强转。

虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类型。而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。意义:数据类型参数化,编译时自动进行类型检查和转换

简单来说,泛型就是来优化上面那个代码的,让它能统一放进你想放的类型,还不需要强制类型转化。解决了上面两个问题。

怎么定义泛型和使用泛型

class 泛型类名称<类型形参列表> {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// 可以只使用部分类型参数
}

所以根据语法,我们可以写出下列代码:

package demo2;

//<T>代表的这是一个泛型类(有<>都是泛型)
class MyArray<T>{
    Object[] array=new Object[10];//1
    //除了上面这一条代码,把下列所有Object替换成T

    public T getPos(int pos){
        return (T)this.array[pos];
    }
    public void setPos(int pos,T x){
        this.array[pos]=x;
    }
}
public class Test {
    public static void main(String[] args) {
       /* MyArray后面加个<>,里面放的是你要存放的类型,
         而后面MyArray的<>,里面可以不写,编译器可以自动判断 */
        MyArray<Integer> myArray=new MyArray<>();//2
        myArray.setPos(1,2);
        myArray.setPos(2,3);\
        int ret=myArray.getPos(1);//3
        myArray.setPos(3,"hello");//4,这时候会编译报错
        String s=(String) myArray.getPos(3);//强转都不行
    }
}
//执行结果
java: 不兼容的类型: java.lang.String无法转换为java.lang.Integer

1. 类名后的代表占位符,表示当前类是一个泛型类  

 了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:

  • E 表示 Element
  • K 表示 Key
  • V 表示 Value
  • N 表示 Number
  • T 表示 Type
  • S, U, V 等等 - 第二、第三、第四个类型

2. 注释1处,不能new泛型类型的数组 

T[] ts = new T[5];//是不对的

3. 注释2处,类型后加入指定当前类型。注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

4. 注释3处,不需要进行强制类型转换

5. 注释4处,代码编译报错,此时因为在注释2处指定类当前的类型,此时在注释4处,编译器会在存放元素的时候帮助我们进行类型检查。   

裸类型(Raw Type)

裸类型是一个泛型类但没有带着类型实参,例如 MyArrayList 就是一个裸类型。

MyArray list = new MyArray();

 注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制。

擦除机制

那么,泛型到底是怎么编译的? 

通过命令:javap -c 查看字节码文件,所有的T都是Object。 

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。 

Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。 

提出问题:

1、那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?

答:我编译的时候不知道你的T是谁,我是在擦除机制擦完之后才知道你的T是谁。所以当我new一个对象时,我必须知道T是谁,它必须有一个具体的类型。否则它语法都无法通过。

2、类型擦除,一定是把T变成Object吗? 

答:在Java中,类型擦除是指在泛型代码编译过程中,编译器将所有泛型类型参数替换为其上界或Object类型。(下个知识点)

额外,注意下列代码: 

class MyArray<T>{
    public T[] array=(T[])new Object[10];
    public T getPos(int pos){
        return (T)this.array[pos];
    }
    public void setPos(int pos,T x){
        this.array[pos]=x;
    }
//返回这个数组
    public T[] getArray(){
        return array;
    }
}
public class Test {
    public static void main(String[] args) {
        MyArray<String> myArray=new MyArray<>();
        myArray.setPos(1,"hello");
        String[] s=myArray.getArray();//运行出错
    }
}
//执行结果
Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String; ([Ljava.lang.Object; and [Ljava.lang.String; are in module java.base of loader 'bootstrap')

为什么这里会报错呢,报的类型转换异常(强转都不行)

问题:既然T的本质是Object,Object又是所有类的父类,那Object给到子类,为什么不行呢?

答:Object是String的父类没错,但是这里是个数组,Object[]就不是String[]的父类了。

泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。 

class 泛型类名称<类型形参 extends 类型边界> {
...
}
//示例
public class MyArray<E extends Number> {
...
}

 只接受 Number 的子类(或者Number自己)型作为 E 的类型实参

MyArray<Integer> l1; // 正常,因为 Integer 是 Number 的子类型
MyArray<String> l2; // 编译错误,因为 String 不是 Number 的子类型

error: type argument String is not within bounds of type-variable E
MyArrayList<String> l2;
^
where E is a type-variable:
E extends Number declared in class MyArrayList

 了解: 没有指定类型边界 E,可以视为 E extends Object

泛型的接口应用 

class findMax<T extends Comparable<T>>{
    public T find(T[] arr){
        T max=arr[0];
        for (int i = 1; i < arr.length; i++) {
            if(arr[i].compareTo(max)>0){
                max=arr[i];
            }
        }return max;
    }
}
public class Test {
    public static void main(String[] args) {
        findMax<Integer> findMax=new findMax<>();
        Integer[] arr={1,4,6,2,1,3};
        System.out.println(findMax.find(arr));
    }
}

 T必须是实现了Comparable接口的,而<T>是Comparable也要是泛型。

泛型方法 

class method{
    public<T extends Comparable> T find(T[] arr){
        T max=arr[0];
        for (int i = 1; i < arr.length; i++) {
            if(arr[i].compareTo(max)>0){
                max=arr[i];
            }
        }return max;
    }
}
public class Test {
    public static void main(String[] args) {
        findMax<Integer> findMax=new findMax<>();
        Integer[] arr={1,4,6,2,1,3};
        System.out.println(findMax.find(arr));
    }
}

 相当于:把接口应用那个方法直接拿起来用,但是要在方法的前面加上<T extends Comparable>

在方法那里加上Static就是静态的泛型方法,使用的时候用类名调用就好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1682240.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenHarmony 3GPP协议开发深度剖析——一文读懂RIL

市面上关于终端&#xff08;手机&#xff09;操作系统在 3GPP 协议开发的内容太少了&#xff0c;即使 Android 相关的学习文档都很少&#xff0c;Android 协议开发书籍我是没有见过的。可能是市场需求的缘故吧&#xff0c;现在市场上还是前后端软件开发从业人员最多&#xff0c…

Hotcoin Research|玩赚WEB3:探索Apeiron:颠覆传统的区块链游戏,融合神话与现代玩法

1. 游戏概述 1.1 游戏类型与主题 Apeiron 是一款结合了上帝模拟、Roguelike、动作角色扮演&#xff08;ARPG&#xff09;和卡牌游戏元素的区块链游戏。这款游戏以独特的方式融合了多种游戏类型&#xff0c;提供了一个丰富多彩的神话宇宙&#xff0c;每个星系都受到不同现实世…

JVM知识点及面试题补充

JVM从软件层面屏蔽了不同操作系统的底层硬件与指令上的区别&#xff08;所谓的Java跨平台能力&#xff09; java中JRE&#xff08;java运行时环境&#xff09;包括java各种Libraries类库以及Java Virtual Machine&#xff08;Java虚拟机&#xff09;。 类加载子系统&#xff1…

Pycharm 编辑器编码格式设置

随笔 目录 1.背景 2. 修改编辑器编码设置 3. 最终修改 yml 写入 1.背景 由于写入yml文件中中文编码问题 ython 中讲数据写入yml 文件后&#xff0c;中文显示&#xff1a; "\u9A8C\u8BC1UDMA0_Tx_C0\u53D1\u9001\u6570\u636EUDMA0_Rx_C1\u65B9\u5411\u63A5\u6536\u65…

总结目前开源的视频生成/视频编辑大模型

Diffusion Models视频生成-博客汇总 前言&#xff1a;随着Sora的爆火&#xff0c;视频生成和视频编辑受到了越来越多的关注。这篇博客总结一下目前开源的视频生成和视频编辑的大模型&#xff0c;并分析他们各自的优缺点&#xff0c;以及在自己进行科研任务或者工作中应该如何选…

Linux网络配置全攻略:解读/etc/network/interfaces文件的精髓

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Linux网络配置全攻略&#xff1a;解读/etc/network/interfaces文件的精髓 前言文件结构与基本概念配置网络接口的常用参数高级网络配置技巧实用工具与调试技巧实战案例与最佳实践 前言 在我们的日常生…

PM入门必备| 怎么写产品分析报告?

​小陪老师&#xff0c;产品经理是做些什么的呢&#xff1f;我去面试应该准备些什么呢&#xff1f; A: 首先要分清产品经理的类型&#xff0c;产品的面试需要准备的一般有Axure原型&#xff0c;需求文档&#xff0c;产品分析报告等&#xff0c;有些甚至需要展示项目经验。 tea…

“遥遥领先” time.sleep(6)?

日前&#xff0c;在一场万众瞩目的发布会上&#xff0c;华为自信满满地揭开了其大模型文生图技术的神秘面纱。然而&#xff0c;演示期间一个不经意间闪现的time.sleep(6)代码片段&#xff0c;如同投入平静湖面的一颗石子&#xff0c;激起了业界对于演示真实性与技术底蕴的热烈探…

Process Monitor下载安装使用教程(图文教程)超详细

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

Ansys Mechanical|中远程点的Behavior该如何设置?

Remote point是ANSYS mechanical中的一种常见节点自由度耦合建模形式&#xff0c;在转动装配体中的连接转动副、或者在施加远端约束及远端载荷的时候&#xff0c;我们经常用到远端单元来耦合一个面或者一条线。例如销轴似的滚动摩擦连接&#xff0c;如果我们希望将两个物体通过…

每日学习 - APK解包

文章目录 APK的定义解析APKAPK 是什么每个文件的意义classes.dexAndroidManifest.xmlassetslibres & resources.arsc 反编译工具apktool apk解包 秒了~ APK的定义 APK&#xff08;Android Package Kit&#xff09;是用于部署和分发Android操作系统上应用程序的软件包格式。…

ASTM通信协议校验和计算方法

Lis通信接口开发 <STX> FN <Frame> <ETB>or<ETX> <CS><CR> <LF> 其中&#xff1a; <STX>&#xff1a;起始帧头&#xff08;0x02&#xff09; FN&#xff1a;帧号&#xff08;范围0&#xff5e;7&#xff0c;1&#xff5e;7完…

Winform自定义控件 —— 开关

在开始阅读本文之前&#xff0c;如果您有学习创建自定义控件库并在其他项目中引用的需求&#xff0c;请参考&#xff1a;在Visual Studio中创建自定义Winform控件库并在其他解决方案中引用https://blog.csdn.net/YMGogre/article/details/126508042 0、引言 由于 Winform 框架并…

Python代码:九、十六进制数字的大小

1、题目 计算的世界&#xff0c;除了二进制与十进制&#xff0c;使用最多的就是十六进制了&#xff0c;现在使用input读入一个十六进制的数字&#xff0c;输出它的十进制数字是多少&#xff1f; 2、代码 import sysnum16 input() num10 int(num16,16) print(num10) 3、结…

GAN实例基于神经网络

目录 1.前言 2.实验 1.前言 需要了解GAN的原理查看对抗生成网络&#xff08;GAN&#xff09;&#xff0c;DCGAN原理。 采用手写数字识别数据集 2.实验 import argparse import os import numpy as np import mathimport torchvision.transforms as transforms from torchvi…

创维汽车总经理培训正式开展,打造新能源汽车销售的精英战队

在新能源汽车市场竞争日益激烈的背景下&#xff0c;创维汽车为加强核心竞争力&#xff0c;于2024年5月15日至17日在河南省安阳市举办了为期三天的总经理岗位认证培训。此次培训旨在强化经销商店端负责人们在新能源汽车销售与运营方面的能力&#xff0c;指明未来发展思路&#x…

(5.4–5.10)投融资周报|共38笔公开投融资事件,基础设施领跑,游戏融资活跃

5月4日至5月10日期间&#xff0c;加密市场共发生38笔投融资事件&#xff0c;其中基础设施18笔、游戏5 笔、其他4 笔、DeFi 3笔、Depin 3 笔、CeFi 2笔、NFT2笔、 RWA1笔。 本周千万美金以上融资有5笔&#xff1a; 加密货币交易公司Arbelos完成了一轮2800 万美元的种子轮融资&…

【极简】docker常用操作

镜像images是静态的 容器container是动态的&#xff0c;是基于镜像的&#xff0c;类似于一个进程。 查看docker images&#xff1a; docker images 或者docker image ls 查看docker container情况&#xff1a;docker ps -a&#xff0c;-a意思是--all 运行一个container: doc…

Python程序设计 文件处理(二)

实验十二 文件处理 第1关&#xff1a;读取宋词文件&#xff0c;根据词人建立多个文件 读取wjcl/src/step1/宋词.txt文件&#xff0c; 注意&#xff1a;宋词文件的标题行的词牌和作者之间是全角空格&#xff08;" ")可复制该空格 在wjcl/src/step3/cr文件夹下根据每…

【WEEK12】 【DAY3】整合MyBatis框架【中文版】

2024.5.15 Wednesday 目录 13.整合MyBatis框架13.1.整合测试13.1.1.新建springboot-05-mybatis项目13.1.2.导入MyBatis需要的依赖13.1.3.配置数据库连接信息13.1.3.1.修改application.properties13.1.3.2.修改Springboot05MybatisApplicationTests.java并测试 13.1.4.新建pojo文…