Collection与数据结构 数据结构预备知识(二):包装类与泛型

news2024/10/6 10:29:35

1.包装类

在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了一个包装类.可以把包装类理解为基本数据类型所对应的引用数据类型.

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

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

除了char和int,其他的都是把首字母大写即可.

1.2 装箱和拆箱

1.2.1 装箱与拆箱的操作

装箱,就是把基本类型转换为包装类型.
拆箱,就是把包装类型转化为基本类型.

public class Package {
    int i = 10;
    //手动装箱操作
    Integer ij = Integer.valueOf(i);
//    Integer iij = new Integer(i);   jdk17已弃用
    //手动拆箱操作
    int a = ij.intValue();
}

上面的valueOf方法为静态方法,所以通过类名来调用.而intValue方法为非静态方法,通过对象名来调用.

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
public int intValue() {
        return value;
    }

既然拆装箱可以手动,当然也可以自动,下面实现自动装箱与自动拆箱

class Auto_Package{
    int a = 10;
    //自动装箱操作
    Integer b = a;
    Integer c = (Integer) a;
    //自动拆箱操作
    int d = b;
    int e = (int) c;
}

1.2.2 包装类的范围问题

下面代码输出什么,为什么?
[阿里巴巴面试题]

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.原因是,包装类的数据有一定地限制范围.下面我们看源码:

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);//超出范围之后就会new一个新的对象出来
    }
private static class IntegerCache {
        static final int low = -128;//范围的最小值为-128
        static final int high;
        static final Integer[] cache;
        static Integer[] archivedCache;

        static {
            // high value may be configured by property
            int h = 127;//定义h=127
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;//范围的最大值为127

由于128超出了if语句的条件限制,所以就会new一个新的对象出来,它们指向的是不同的引用,而 == 比较的就是两个对象的地址是否想相同,所以第二个返回false.

2.泛型

2.1 什么是泛型

一般的类和方法,只能使用具体的类型,要不是基础类型,要不是引用类型,要不是自定义类型,如果需要编写多种类型都可以应用的代码,这种编程方式就会特别刻板.
于是在jdk1.5中就引入了新的语法,就是泛型:通俗讲,就是适用于多种类型.从代码上讲,就是把类型作为一种参数来传递,实现的是类型的参数化.

2.2 引出泛型

实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值?我们现在通过已有的知识来实现.

class MyArray{
    public Object[] array = new Object[10];//通过object类实现存储任何类型元素
    public void setPos(int pos,Object val){
        this.array[pos] = val;//设置元素
    }
    public Object getPos(int pos){
        return array[pos];//获取元素
    }
}
public class Main {
    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.setPos(1,2);
        myArray.setPos(2,"String");
        String str = (String) myArray.getPos(2);//Object类向下转型
        System.out.println(str);
    }
}    

上述的数组可以存放任何类型的数据,但是更多情况下,我们还是希望能够只有一种数据类型,所以,泛型的目的就是指定当前容器要持有什么类型的对象,让编译器做检查.此时就需要把类型作为参数传递.

2.3 语法

class className<T1,T2,T3....>{
//这里可以使用指定的参数类型
}

我们对上述代码进行改写:

class MyArray2<T>{
    public T[] array = (T[]) new Object[10];//这种创建数组的方法其实不太好,我们后面说为什么,1
    public void setPos(int pos,T val){
        this.array[pos] = val;
    }
    public T getPos(int pos){
        return array[pos];
    }
}
public class Main {
    public static void main(String[] args) {
        MyArray2<Integer> myArray2 = new MyArray2<>();//2
        myArray2.setPos(1,2);
        myArray2.setPos(2,3);
        myArray2.setPos(3,4);
        int i = myArray2.getPos(3);//3
        System.out.println(i);
        //myArray2.setPos(4,"String");//4
    }
}

代码解释:

  1. 类名后的 < T >代表占位符,表示当前类型是一个泛型.
    类型的指定一般用一个大写字母来表示,常见的有:
    E 表示 Element
    K 表示 Key
    V 表示 Value
    N 表示 Number
    T 表示 Type
    S, U, V 等等 - 第二、第三、第四个类型
  2. 注释1处不可以new泛型的数组,T[] t = new T[5]不正确.后面new对象的时候尖括号中可以不写内容,是因为编译器可以根据上下文推导出类型实参.
  3. 注释2处<Integer>指定了当前对象的类型.
  4. 注释3处,无需强转,自动拆包.
  5. 注释4处报错,传入的字符串类型和Integer类型呢不匹配.

2.4 泛型编译原理

泛型是如何编译的呢,它遵循的是擦除机制,就是把所有的T擦除为Object.
Java的泛型机机制是编译时实现的,生成的字节码文件之后并不存在泛型的这种概念.

2.5为什么不能实例化泛型类型的数组

class MyArray3<T>{
    public T[] ts = (T[]) new Object[5];
    public T getPos(int pos){
        return ts[pos];
    }
    public T[] getTs(){
        return ts;
    }
}
public class Main {
    public static void main(String[] args) {
        MyArray3<Integer> myArray3 = new MyArray3<>();
        Integer[] integers = myArray3.getTs();
    }
}

在这里插入图片描述
这里我们看到,出现了类型转换异常,是因为在返回数组的操作中,T被擦除为了Object,而Object数组中可以存放任何类型的元素,而要把Object类型的数组传给一个Integer数组,编译器认为是不安全的.所以会出现异常.

接下来,我们解释为什么强转为(T[])类型的数组是不妥当的,其实和上面的问题是一样的道理,都是在类型中出现了问题.
在这里插入图片描述
上述我们可以看到编译器给出了警告,意思就是你Object类型数组里的元素要往T去转(向下转型),不一定都可以转成功,比如在new这个类型的对象的时候,T给的是一个Integer类型,而Object类型中的元素若是有String类型,这时就强转不了.我们前面提到向下转型本来就不安全,所以向下转型一定要谨慎.

正确的做法如下:

class MyArray4<T>{
    public Object[] array = new Object[10];
    public T getPos(int pos){
        return (T)array[pos];//这里虽然会报警告,但是在创建这个类的对象的时候,就已经指定了
        //类型,所以在添加的时候就是添加的这个类型,所以这里的强转是安全的
    }
    public void setPos(int pos,T val){
        array[pos] = val;//这里给数组放入的数据类型和创建对象时指定的T的类型是一致的
    }
}

2.6 泛型的上界

在定义泛型类的时候,有时需要对传入的类型进行一定的约束

2.6.1 语法

public class MyArray<类型形参 extends 类型边界> {
	........
}

实例1:

public class MyArray<T extends Number> {//传入的类型必须继承自Number
	........
}

实例2:

public class MyArray<E extends Comparable<E>>{//传入的类型必须实现comparable接口,即可比较对象
	...
}

2.7 泛型方法

2.7.1 语法

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

下面结合泛型上界和泛型方法来举个例子

class Alg{
    public <E extends Comparable<E>> E findMaxVal(E[] array){
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (max.compareTo(array[i])>0){
                max = array[i];
            }
        }
        return max;
    }
}
public class Main {
    public static void main(String[] args) {
        Integer[] array = {1,2,3,4,5};
        Alg alg = new Alg();
        System.out.println(alg.findMaxVal(array));
    }
}

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

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

相关文章

AJAX-综合

文章目录 同步代码和异步代码回调函数地狱解决回调函数地狱Promise-链式调用async函数和awaitasync函数和await-捕获错误 事件循环宏任务与微任务Promise.all静态方法 同步代码和异步代码 同步代码&#xff1a;逐步执行&#xff0c;需原地等待结果后&#xff0c;才继续向下执行…

LLM漫谈(五)| 从q star视角解密OpenAI 2027年实现AGI计划

最近&#xff0c;网上疯传OpenAI2027年关于AGI的计划。在本文&#xff0c;我们将针对部分细节以第一人称进行分享。​ 摘要&#xff1a;OpenAI于2022年8月开始训练一个125万亿参数的多模态模型。第一个阶段是Arrakis&#xff0c;也叫Q*&#xff0c;该模型于2023年12月完成训练&…

微软Microsoft Surface Go 2

1个小玩具 Microsoft Surface Go 2的评测结果出炉&#xff01;它是目前最好的中端Windows 二合一笔记本平板。 外形简洁小巧&#xff0c;工作娱乐两不误。 它有多个版本。 我们测试的是配备8GB Ram和128GB SSD的Pentium 4425Y处理器&#xff08;第8代&#xff09;的型号。 S…

力扣242. 有效的字母异位词

思路&#xff1a;字母相互抵消的思路&#xff0c;本题字符串中只包含小写字母26位&#xff0c;那就新建record数组int[26]&#xff0c;下标0-25&#xff0c;代表小写字母a-z, 需要通过 某字符减a 来达到这一目的&#xff1b; class Solution {public boolean isAnagram(String…

Oracle 使用OGG(Oracle GoldenGate) 实现19c PDB与MySQL5.7 数据同步

OGG 是一种基于日志的结构化数据复制软件&#xff0c;它通过解析源数据库在线日志或归档日志获得数据的增删改变化。 OracleMysqlIP address192.168.80.100192.168.80.16DB version19.2.05.7host nametempmysql OS version&#xff1a; CentOS 7.9 一&#xff0c;Oracle 服务…

[数据结构]二叉树(下)

一、二叉树的节点和深度关系 1.满二叉树 我们可以假设二叉树有N个节点&#xff0c;深度为h我们可以恒容易得到满二叉树每行的节点数&#xff0c;然后错位相减,算出节点与高度的关系。 2.完全二叉树 注意我这个是因为最后一行的节点数为1。 二、向上调整建堆和向下调整建堆的时…

NFT交易市场-后端开发

首先我们需要配置好我们的ipfs&#xff0c;参考官方文档 1.https://docs.ipfs.tech/install/command-line/#system-requirementshttps://docs.ipfs.tech/how-to/command-line-quick-start/#initialize-the-repository 首先新建一个文件夹 然后在终端输入npm init -y命令进行初…

【数据结构】顺序表习题之移除元素和合并两个有效数组

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《数据结构》 &#x1f389;道阻且长&#xff0c;行则将至 前言 嗨呀&#xff0c;今天的博客是关于顺序表的两道题目&#xff0c;是力扣的移除元素和合并有序数组的题目。 一.移除…

java selenium 元素点击不了

最近做了一个页面爬取&#xff0c;很有意思被机缘巧合下解决了。 这个元素很奇怪&#xff0c;用xpath可以定位元素&#xff0c;但是就是click()不了。 试过了网上搜的一些办法&#xff1a; //尝试一 WebElement a_tag driver.findElement(By.xpath("xxx")); a_tag…

今天聊聊新零售

一、什么是新零售&#xff1f; 2016年&#xff0c;在杭州举行的“云栖大会”上&#xff0c;马云发表了讲话&#xff0c;首次提出了“新零售”这一概念。 1.1 新零售概念 新零售&#xff0c;英文是New Retailing&#xff0c;新零售是对人货场的重构。人是消费者、销售人员、…

Linux:Jenkins全自动持续集成持续部署(3)

在上一章部署好了之后&#xff0c;还需要点击一下才能进行部署&#xff0c;本章的效果是&#xff1a;当gitlab上的代码发生了变化后&#xff0c;我们不需要做任何事情不需要去点击构建按钮&#xff0c;Jenkins直接自动检测变化&#xff0c;然后自动去集成部署Linux&#xff1a;…

jmeter参数化--CSV数据驱动

主要是用来接口测试正例反例测试。 http请求下添加csv数据文件设置 进行csv配置 1、首先创建csv文件 内容第一行输入变量名&#xff0c;逗号隔开 下面输入正常异常的测试值及对应的校验结果。 2、CSV数据文件配置 文件名路径选择上面创建的csv文件 编码选utf-8 变量名与csv…

【深度学习】四种天气分类 模版函数 从0到1手敲版本

引入该引入的库 import torch import torch.nn as nn import matplotlib.pyplot as plt import torch.nn.functional as F import torchvision import torch.optim as optim %matplotlib inline import os import shutil import glob os.environ["KMP_DUPLICATE_LIB_OK&q…

【数据挖掘】实验5:数据预处理(1)

实验5&#xff1a;数据预处理&#xff08;1&#xff09; 一&#xff1a;实验目的与要求 1&#xff1a;熟悉和掌握数据预处理&#xff0c;学习数据清洗、数据集成、数据变换、数据规约、R语言中主要数据预处理函数。 二&#xff1a;实验内容 【缺失值分析】 第一步&#xff1…

Python工具-清理Unity(批量深度)清理U3D项目工程保留关键工程文件

前沿 1. Unity工程越来越多&#xff0c;很久不用的工程里存在了很多无用的大文件夹&#xff0c;极大的影响电脑容量。 2. 我电脑里面U3D工程只有17个&#xff0c;但容量就高达60GB&#xff0c;使用自己编写的工具清理后&#xff0c;减到了30GB多。清理了不是很重要的文件和文件…

2024-03-22 问AI: 介绍一下深度学习中的 sigmoid函数

文心一言 Sigmoid函数是深度学习中常用的一种激活函数&#xff0c;主要用于将神经元的输出值压缩到0和1之间。这种特性使得sigmoid函数在二分类问题中特别有用&#xff0c;因为输出值可以被解释为属于某个类别的概率。 sigmoid函数的数学表达式为&#xff1a; σ(x) 1 / (1…

Notepad++ 如何调整显示字面大小

在 Notepad 上&#xff0c;可以使用 ctrl 加上鼠标的左键来滚动来进行调整。 如何恢复默 可以使用 Ctrl 加数字键盘上的 / 键 来恢复默认设置。 当然也可以通过菜单栏上 view 菜单下的 Zoom 选项。 上面的界面中可以看到我们的在 Notepad 中使用的选项。 Notepad 如何调整显示…

llvm后端

SelectionDAGBuilder是LLVM&#xff08;Low Level Virtual Machine&#xff09;编译器中的一个重要组件&#xff0c;它负责将LLVM中间表示&#xff08;Intermediate Representation&#xff0c;IR&#xff09;转换为SelectionDAG&#xff08;选择有向无环图&#xff09;的形式。…

RabbitMq高可用

消息队列高级 服务异步通信-高级篇1.消息可靠性1.1.生产者消息确认1.2.消息持久化1.3.消费者消息确认1.4.消费失败重试机制1.5.总结 2.死信交换机2.1.初识死信交换机2.2.TTL2.3.延迟队列 3.惰性队列3.1.消息堆积问题3.2.惰性队列 4.MQ集群4.1.集群分类4.2.普通集群4.3.镜像集群…

C#,图论与图算法,计算图(Graph)的岛(Island)数量的算法与源程序

1 孤岛数 给定一个布尔矩阵,求孤岛数。一组相连的1形成一个岛。例如,下面的矩阵包含5个岛: 在讨论问题之前,让我们先了解什么是连接组件。无向图的连通分量是一个子图,其中每两个顶点通过一条路径相互连接,并且不与子图外的其他顶点连接。 所有顶点相互连接的图只有一个…