【数据结构】_包装类与泛型

目录

1. 包装类

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

1.2 (自动)装箱和(自动)拆箱

1.2.1 装箱与拆箱

1.2.2 自动(显式)装箱与自动(显式)拆箱

1.3 valueOf()方法

2. 泛型类

2.1 泛型类与Object类

2.2 泛型类语法

2.3 泛型类示例

2.4 裸类型(Raw Type)

2.5 泛型类的编译

2.5.1 擦除机制

2.5.2 泛型类型数组的实例化

2.6 泛型的上界

2.6.1  N为接口

 2.6.2   Number为类

3. 泛型方法

3.1 语法

3.2 泛型方法示例

3.2.1 普通类的普通泛型方法

3.2.2 普通类的静态泛型方法


1. 包装类

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

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

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

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

1.2 (自动)装箱和(自动)拆箱

1.2.1 装箱与拆箱

装箱(装包):把基本数据类型变为对应的包装类型;

拆箱(拆包):把引用类型变为基本数据类型;

1.2.2 自动(显式)装箱与自动(显式)拆箱

代码示例1:自动装箱与显式装箱:

        int a = 10;
        // 自动装箱
        Integer val = a;
        System.out.println(val);
        // 显式装箱
        Integer val2 = Integer.valueOf(a);
        Integer val3 = new Integer(a);
        System.out.println(val2);
        System.out.println(val3);

 代码示例2:自动拆箱:

        Integer val1 = 10;
        // 自动拆箱
        int a = val1;
        System.out.println(a);
        // 显式拆箱
        // 拆为int类型
        int a2 = val1.intValue();
        System.out.println(a2);
        // 拆为double类型
        double a3 = val1.doubleValue();
        System.out.println(a3);

 注:(1)自动装箱的底层逻辑:Integer包装类的valueOf()方法: 

(2)自动拆箱的底层逻辑:Integer包装类的intValue()方法:

(3)显式拆箱时,Integer包装类不止提供了intValue()方法,还提供了doubleValue()等方法:

可以根据所需的基本类型对应调用其方法,在上文示例中,输出结果为:

1.3 valueOf()方法

试运行以下代码:

        Integer a = 127;
        Integer b = 127;
        System.out.println(a==b);
        Integer c = 128;
        Integer d = 128;
        System.out.println(c==d);

输出结果为:

原理注解:

(1)Integer包装类的valueOf方法源代码与方法内部相关量的值:

(2)方法含义:

如果i在[low, high]即[-128, 127]之间,则返回cache缓存数组中下标为i+128位置的元素:

如i=0时存储在cache[128],i=-128时则存储在cache[0],i=127时则存储在cache[255];

即在缓存数组中存储了256个数字;

在该范围内的i调用valueOf方法调用到的是同一个元素,故而a=b;

在该范围外的i调用valueOf方法会new Integer对象,作为引用类型,==判断的是引用类型是否是对一个对象,故而a!=b;

2. 泛型类

一般的类和方法只能使用具体的类型:基本类型或自定义类,泛型就是适用于多种类型,即对参数实现了参数化;

2.1 泛型类与Object类

现要求实现一个不限制元素种类的数组,联想到Object类,示例代码如下:

class MyArray{
    public Object[] obj = new Object[3];
    public Object getPos(int pos){
        return obj[pos];
    }
    public void setPos(int pos,Object val){
        obj[pos]=val;
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.setPos(0,10);
        myArray.setPos(1,"hello");
        myArray.setPos(2,10.0);
        double ret = myArray.getPos(2);
        System.out.println(ret);
    }
}

报错如下:

 如要创建double类型变量对数组元素进行接收,则需要进行强转:

double ret = (double)myArray.getPos(2);

上文设计的数组具有以下特点:

① 任何数据都可以存储; ② 获取数据时必须进行强制类型转换;

这并非我们需要实现的泛型数组,通常需要实现的泛型数组需求是:存储一种类型的数据;

泛型编程是将类型作为参数传递的编程方式,目的是指定当前容器后可以存放某一种类型的数据;

2.2 泛型类语法

// 泛型的一般使用方法
class 泛型类名称<类型形参列表>{
}
class ClassName<T1,T2...Tn>{
}

// 泛型类的继承
class 泛型类名称<类型形参列表> extends 继承类{
}
class ClassName<T1,T2,...Tn> extends ParentClass<T1>{
}

注:① 类名后的<T>代表占位符,表示当前类是一个泛型类,

类型形参一般使用一个大写字母表示,常用名称有:

E表示Element,K表示Key,V表示Value,N表示Number,T表示Type;

泛型当中不能实例化一个泛型类型的数组,如:

T[] ts = new T[5];

是错误的;

③ 泛型类实例化的同时会指定当前泛型类的指数参数类型,如果二者冲突,就会报错,

这也是泛型编程的一个意义所在:泛型编程在程序编译时,存储数据时自动进行类型检查; 

2.3 泛型类示例

class MyArray<T>{
    public T[] obj = (T[])new Object[3];
    public T getPos(int pos){
        return obj[pos];
    }
    public void setObj(int pos, T val){
        obj[pos]=val;
    }
}
public class Demo1 {
    public static void main(String[] args) {
        // 实例化对象的同时指定当前泛型类的指定参数类型
        // 指定参数的类型必须是引用类型,如int非法而Integer合法
        MyArray<Integer> myArray1 = new MyArray<Integer>();
        myArray1.setObj(0,10);
        myArray1.setObj(1,78);
        myArray1.setObj(2,66);
        double ret1= myArray1.getPos(1);
        System.out.println(ret1);
        System.out.println("-------------------");
        MyArray<String> myArray2 = new MyArray<String>();
        myArray2.setObj(0,"hello");
        myArray2.setObj(1,"world");
        myArray2.setObj(2,"java");
        String ret2 = myArray2.getPos(1);
        System.out.println(ret2);
    }
}

输出结果为:

2.4 裸类型(Raw Type)

裸类型是一个泛型类但没有带类型实参,例如:

class MyArray<T>{
    public T[] obj = (T[])new Object[3];
    public T getPos(int pos){
        return obj[pos];
    }
    public void setObj(int pos, T val){
        obj[pos]=val;
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyArray list = new MyArray();
    }
}

但请注意:裸类型是为了兼容老版本的API,在编程时请避免裸类型的使用;

2.5 泛型类的编译

2.5.1 擦除机制

class MyArray<T>{
    public T[] obj = (T[])new Object[3];
    public T getPos(int pos){
        return obj[pos];
    }
    public void setObj(int pos, T val){
        obj[pos]=val;
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<Integer>();
        myArray.setObj(0,85);
        int ret = myArray.getPos(0);
        System.out.println(ret);
    }
}

查看上文代码的字节码文件:

在编译完成后,运行过程中是没有泛型的概念的,此时所有的T都被擦除为Object,通过上述的编译器生成的字节码文件中是不包含泛型的类型信息的;

2.5.2 泛型类型数组的实例化

java语法规定:在实例化数组时必须提供具体的元素类型,故而不能直接实例化泛型类型数组

方法1:(上文擦除机制部分示例代码的在泛型类中创建数组的方法):

class MyArray<E>{
    public E[] obj = (E[]) new Object[3];
}

但该种写法存在问题:试运行以下代码:

class MyArray<E>{
    public E[] obj = (E[]) new Object[3];

    public E getPos(int pos){
        return obj[pos];
    }
    public void setObj(int pos,E val){
        obj[pos]=val;
    }
    // 返回数组的方法
    public E[] getArray(){
        return obj;
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<Integer>();
        myArray.setObj(0,10);
        myArray.setObj(1,85);
        Integer[] integers = myArray.getArray();
    }
}

报错及分析如下:

在继承与多态章节已经提到过,向下转型是不安全的;

java的数组实现非常特殊,

此处可以理解为:jvm认为使用一个固定类型如Integer或String等等类型的对象来接收Object类型对象是不安全的;

正确代码为:(使用反射)

class MyArray<E>{
    public E[] obj;
    public MyArray(Class<E>clazz, int capacity){
        // 参数为数组元素类型与容量
        obj = (E[])Array.newInstance(clazz, capacity);
    }
    public E getPos(int pos){
        return obj[pos];
    }
    public void setObj(int pos, E val){
        obj[pos]=val;
    }
    public E[] getArray(){
        return obj;
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>(Integer.class,10);
        myArray.setObj(0,1997);
        myArray.setObj(1,85);
        Integer[] integers = myArray.getArray();
    }
}

但以上方法并不常用,更推荐方法2:; 

继承与多态文章链接如下:

CSDN

方法2:参考java的ArrayList源码的get方法:

对于泛型类型数组的实例化,不能直接使用泛型类型作为数组元素的类型,故而可以使用Object类结合强制类型转换实现泛型类型数组的实例化:

class MyArray<E>{
    public Object[] obj = new Object[3];
    public E getPos(int pos){
        return (E)obj[pos];
    }
    public void setPos(int pos, Object val){
        obj[pos] = val;
    }
}

2.6 泛型的上界

2.6.1  <E extends N> N为接口

表示实例化对象时指定的参数类型一定已经实现了N接口;

// 写一个泛型类求一个数组的最大值
class Alg<E extends Comparable<E>>{
    public E findMax(E[] array){
        E max=array[0];
        for(int i=0;i<array.length;i++){
            if(max.compareTo(array[i])<0){
                max = array[i];
            }
        }
        return max;
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Alg<Integer> alg = new Alg<Integer>();
        Integer[] array = {1,4,2,10,9,8,17,5};
        System.out.println("Array is:");
        for(Integer x:array){
            System.out.print(x+" ");
        }
        System.out.println();
        Integer val =  alg.findMax(array);
        System.out.println("The max element in the array is "+val);
    }
}

输出结果为:

   

 2.6.2  <E extends Number> Number为类

表示E是Number的子类或E就是Number本身;

参考Number (Java Platform SE 8 ) (oracle.com)

 Integer、Double、Long、Short等等都是Number常见的直接子类:

class A<E extends Number>{
    A<Number> a1 = new A<>();
    A<Integer> a2 = new A<>();
    A<Double> a3 = new A<>();
    // A<String> a4 = new A<>();
}

3. 泛型方法

3.1 语法

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

3.2 泛型方法示例

3.2.1 普通类的普通泛型方法

class Alg2{
    public<E extends Comparable> E findMax(E[] array){
        E max = array[0];
        for(int i=0;i<array.length;i++){
            if(max.compareTo(array[i])<1){
                max=array[i];
            }
        }
        return max;
    }
}
public class Demo4 {
    public static void main(String[] args) {
        Alg2 alg2 = new Alg2();
        Integer[] arr = {19,9,7,85,25};
        System.out.println("Array is: ");
        for(Integer x:arr){
            System.out.print(x+" ");
        }
        System.out.println();
        Integer val = alg2.<Integer>findMax(arr);
        System.out.println("The max element in the array is "+val);
    }
}

输出结果为:

 注:调用泛型方法时泛型类型可以省略:

 Integer val = alg2.<Integer>findMax(arr);

 上行代码可以简写为:

 Integer val = alg2.findMax(arr);

编译器会根据传递给泛型方法的参数arr的类型判断E的类型;

3.2.2 普通类的静态泛型方法

class Alg2{
    public static<E extends Comparable> E findMax(E[] array){
        E max = array[0];
        for(int i=0;i<array.length;i++){
            if(max.compareTo(array[i])<1){
                max=array[i];
            }
        }
        return max;
    }
}
public class Demo4 {
    public static void main(String[] args) {
        Integer[] arr2 = {19,9,7,85,25};
        System.out.println("Array is: ");
        for(Integer x:arr2){
            System.out.print(x+" ");
        }
        System.out.println();
        Integer val = Alg2.findMax(arr2);
        System.out.println("The max element in the array is "+val);
    }
}

输出结果为:

静态泛型方法不再依赖于类的对象存在,可以使用类名直接调用;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

bert 相似度任务训练完整版

任务 之前写了一个相似度任务的版本&#xff1a;bert 相似度任务训练简单版本,faiss 寻找相似 topk-CSDN博客 相似度用的是 0&#xff0c;1&#xff0c;相当于分类任务&#xff0c;现在我们相似度有评分&#xff0c;不再是 0,1 了&#xff0c;分数为 0-5&#xff0c;数字越大…

ChatGPT最新功能“Text To Speech (TTS,文本转语音)”详细解读!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

Windows环境MySQL全量备份+增量备份

一、环境准备 1.1.安装MySQL 在进行MySQL数据库备份和还原操作时&#xff0c;必须先提前安装好MySQL环境&#xff0c;且MySQL服务已成功开启 如果没有安装MySQL环境&#xff0c;可以参考博客&#xff1a;http://t.csdnimg.cn/h8bHl 如果已成功安装MySQL环境&#xff0c;打开…

Orbit 使用指南 02 | 在场景中生成原始对象| Isaac Sim | Omniverse

如是我闻&#xff1a; Orbit使用指南02将 深入探讨如何使用Python代码在Orbit中向场景生成各种对象&#xff08;或原始对象&#xff09;。一起探索如何生成地面平面、灯光、基本图形形状以及来自USD文件的网格。前置知识&#xff1a;如何生成空白场景&#xff0c;Orbit 使用指…

VUE实现Office文档在线编辑,支持doc/docx、xls/xlsx、ppt/pptx、pdf等

1.微软提供的在线Office预览&#xff08;只能预览&#xff0c;不能编辑&#xff09; https://view.officeapps.live.com/op/view.aspx?src服务器上文档地址&#xff08;http开头&#xff09; 2.国内在线Office方案&#xff1a; 腾讯文档、石墨文档、飞书 优势&#xff1a;跨…

paimon取消hive转filesystem

目录 概述实践关键配置spark sql 结束 概述 公司上一版本保留了 hive &#xff0c;此版优化升级后&#xff0c;取消 hive。 实践 关键配置 同步数据时&#xff0c;配置如下&#xff0c;将形成两个库 # ods库 CREATE CATALOG paimon WITH (type paimon,warehouse hdfs:///d…

CentOS配网报错:network is unreachable

常用命令&#xff1a; 打开&#xff1a; cd /etc/sysconfig/network-scripts/ 修改&#xff1a; vim ifcfg-ens33 打开修改&#xff1a; vim /etc/sysconfig/network-scripts/ifcfg-ens33 保存&#xff1a; 方法1&#xff1a;ESCZZ&#xff08;Z要大写&#xff09; 方…

熔断降级 spring事务

如果有事务处理&#xff0c;会先把事务的自动提交给关闭

Apache Flink连载(三十七):Flink基于Kubernetes部署(7)-Kubernetes 集群搭建-3

🏡 个人主页:IT贫道-CSDN博客 🚩 私聊博主:私聊博主加WX好友,获取更多资料哦~ 🔔 博主个人B栈地址:豹哥教你学编程的个人空间-豹哥教你学编程个人主页-哔哩哔哩视频 目录

32单片机基础:PWM驱动舵机,直流电机

PWM驱动舵机 接线图如上图所示。注意&#xff0c;舵机的5V 线不能接到面包板上的正极&#xff0c;面包板上的正极只有3.3V,是STM32提供的&#xff0c;所以要接到STLINK的5V, 我们如何驱动舵机呢&#xff1f;由之前我们介绍原理知道&#xff0c;要输出如下图对应的PWM波形才行…

202209 青少年软件编程等级考试Scratch二级真题

第 1 题 【 单选题 】 数字&#xff1a;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;6&#xff0c;9&#xff0c;13&#xff0c;19&#xff0c;28&#xff0c;...的下一项是多少&#xff1f; A&#xff1a;37 B&#xff1a;39 C&#xff1a;41 D&#xff1a;47 …

爱奇艺2023年营收319亿元:完善服务价值感知,重构影视新生态

近日&#xff0c;爱奇艺&#xff08;NASDAQ:IQ&#xff09;发布截至2023年12月31日未经审计的第四季度和全年财报&#xff0c;这份财报被外界评价为“爱奇艺交出的年度最佳业绩”。 财报显示&#xff0c;爱奇艺全年总营收319亿元&#xff0c;同比增长10%&#xff1b;非美国通用…

模拟器抓HTTP/S的包时如何绕过单向证书校验(XP框架)

模拟器抓HTTP/S的包时如何绕过单向证书校验&#xff08;XP框架&#xff09; 逍遥模拟器无法激活XP框架来绕过单向的证书校验&#xff0c;如下图&#xff1a; ​​ 解决办法&#xff1a; 安装JustMePlush.apk安装Just Trust Me.apk安装RE管理器.apk安装Xposedinstaller_逍遥64位…

Java SE:反射

反射作用 获取字节码文件里面的所有信息&#xff0c;包括构造方法、成员、成员方法&#xff0c;以及修饰他们的修饰符、类型和方法的返回值等等&#xff0c;只要是类里面的内容都能获取&#xff0c;获取之后可以动态的调用方法&#xff0c;动态的创建对象 获取类字节码文件对象…

vue3中的基本语法

目录 基础素材 vue3的优化 使用CompositionAPI理由 1. reactive() 函数 2. ref() 函数 2.1. ref的使用 2.2. 在 reactive 对象中访问 ref 创建的响应式数据 3. isRef() 函数 4. toRefs() 函数 5. computed() 5.1. 通过 set()、get()方法创建一个可读可写的计算属性 …

“耳机党”注意了!你的耳机,用对了吗?

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f3e1; 什么是“3个60”原则&#xff1f; &#x1f3e1;&#x1f4d2; 如何遵循“3个60”原则&#xff1f; &#x1f4d2;&#x1f4dd; 控制音量&#x1f4dd; 适时休息&#x1f4dd; 关注外界声音 &#x1f4d6; 介绍 &…

深度学习目标检测】二十二、基于深度学习的肺炎检测系统-含数据集、GUI和源码(python,yolov8)

肺炎尽管很常见&#xff0c;但准确诊断是一项困难的任务。它要求训练有素的专家对胸部X光片进行检查&#xff0c;并通过临床病史&#xff0c;生命体征和实验室检查进行确认。肺炎通常表现为胸部X光片上一个或多个区域的阴影(opacity)增加。但是&#xff0c;由于肺部有许多其他状…

足球青训俱乐部|基于Springboot的足球青训俱乐部管理系统设计与实现(源码+数据库+文档)

足球青训俱乐部管理系统目录 目录 基于Springboot的足球青训俱乐部管理系统设计与实现 一、前言 二、系统设计 1、系统架构设计 三、系统功能设计 1、管理员登录界面 2、公告信息管理界面 3、学员管理界面 4、商品信息管理界面 5、课程安排管理界面 四、数据库设计…

机器学习:主成分分析笔记

主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;是一种无监督的机器学习算法&#xff0c;通常用于高维数据的降维、提取主要特征、数据降噪和可视化。PCA的基本思想是将原始数据的多个变量转换为少数几个相互独立的变量&#xff08;即主成分&a…

上海亚商投顾:深成指震荡涨超1% 两市成交连续破万亿

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指3月1日震荡反弹&#xff0c;深成指、创业板指午后涨超1%。充电桩概念股集体走强&#xff0c;英可瑞、欧陆…