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

news2024/11/13 14:39:46

目录

1. 包装类

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

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

1.2.1 装箱与拆箱

1.2.2 自动装箱与自动拆箱

1.3 valueOf()方法

2. 泛型类

2.1 泛型类与Object类

2.2 泛型类语法

2.3 泛型类示例

2.4 裸类型

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 裸类型

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

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:; 

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

https://mp.csdn.net/mp_blog/creation/editor/129814488

方法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.coloradmin.cn/o/547831.html

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

相关文章

怎么把照片缩小到200k?图片指定大小压缩怎么弄?

平时在给账号设置头像时&#xff0c;都会遇到图片过大无法上传的情况&#xff0c;这时候我们可以通过图片压缩指定大小工具来将图片压缩到200kb以下&#xff0c;这样就可以顺利设置头像了&#xff0c;下面一起来看一下图片指定大小压缩&#xff08;https://www.yasuotu.com/ima…

机器学习笔记 - windows基于TensorRT的UNet推理部署

一、TensorRT简介 NVIDIA TensorRT是一个用于高性能深度学习推理的平台。TensorRT适用于使用CUDA平台的所有NVIDIA GPU。所以如果需要基于TensorRT部署,至少需要一个NVIDIA显卡,算力5.0以上,比Maxwell更新的架构,可以参考下表。 CUDA GPUs - Compute Capability | NVIDIA …

电动车头盔检测数据集

现在正慢慢整理自己有关电动车头盔检测的项目内容&#xff0c;会逐渐将这些资源进行发布&#xff0c;供大家参考和使用【部分资源有偿提供&#xff0c;毕竟花费了很多心血】。 这篇文章主要是发布相关数据集的。网上关于工厂环境下的头盔数据集有很多&#xff0c;而且多种多样…

PFCdocumentation_Coupling PFC and FLAC3D

目录 Coupling PFC and FLAC3D 1D Structural Element Coupling Scheme Wall-Zone Coupling Scheme 2D 3D Ball-Zone Coupling Scheme Commands FISH Functions Coupling PFC and FLAC3D 在 FLAC3D 图形用户界面中&#xff0c;可以通过“工具 ‣ 加载 PFC”菜单项加载 …

计算机组成与结构易错题

计算机组成与结构 海明校验码是在n个数据位之外增设k个校验位&#xff0c;从而形成一个kn位的新的码字&#xff0c;使新的码字的码距比较均匀地拉大。n与k的关系是&#xff08;A&#xff09;。 A、2k-1≥nk B、2n-1≤nk C、nk D、n-1≤k 知识&#xff1a; 确定要传输的信息&…

普通专科生,拿什么拯救自己的未来我想成为一名网络安全专业人员,需要做什么?

前 言 写这篇文章的初衷是很多朋友都想了解如何入门/转行网络安全&#xff0c;实现自己的“黑客梦”。文章的宗旨是&#xff1a; 1.指出一些自学的误区 2.提供客观可行的学习表 3.推荐我认为适合小白学习的资源.大佬绕道哈&#xff01; 我的经历&#xff1a; 我19年毕业&…

【C语言】入门必看之循环练习(含二分查找动图)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;C语言 ⚡注&#xff1a;此篇文章的 代码风格部分 将根据《高质量 C/C 编程指南》 —— 林锐 进行说明。该部分将用紫色表示 该篇将对循环语…

AI落地:10分钟变身Excel高手

本文首发公众号突围一只鹰。 使用Excel的时候经常有几个难点&#xff1a; 有些功能不知道如何操作不知道该用哪个公式不知道公式的参数如何设置复杂数据处理不知道如何写公式多表链接的时候不知道如何写公式其他数据源导入Excel只会手动录入 有了ChatGPT之后&#xff0c;很多…

求爷爷告奶奶,阿里大佬才甩出这份Spark+Hadoop+中台实战pdf

Spark大数据分析实战 1、Spark简介 初识Spark Sp ark生态系统BDAS Sp ark架构与运行逻辑 弹性分布式数据集 2、Spark开发与环境配置 Spark应用开发环境2置 使用Intelli i开发Spark 远程调试Spark程序 Spark编译 配置Spark源码阅读环境 3、BDAS简介 SQL on Spark S…

Windows使用flask部署HTML网页的方法

使用Flask python运行设计的好的html网页&#xff0c;已经配套的css和js文件&#xff1a; 前提条件 html、css 和 js 在同一个目录之下 html 内使用 css 和 js &#xff0c;需要使用相对路径flask python 程序可以和 html 不在同一个目录 即&#xff1a;python程序可以在D盘…

sql server 数据库

1、窗口函数 sqlserver中窗口函数和OVER()函数_lfw2019的博客-CSDN博客参考&#xff1a;https://blog.csdn.net/qq_41805514/article/details/81772182 https://blog.csdn.net/qq_27997957/article/details/82383328一、OVER() 函数  语法结构&#xff1a;OVER([ PARTITION B…

【C++初阶】动态内存管理

一.C内存分布 说明&#xff1a; 1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等&#xff0c;栈是向下增长的&#xff1b; 2. 内存映射段是高效的I/O映射方式&#xff0c;用于装载一个共享的动态内存库。用户可使用系统接口 创建共享共享内存&#xff0c;做进程间通信&…

【Leetcode刷题】算法:合并两个有序链表

文章目录 一、题目介绍二、解决办法三、提交结果 一、题目介绍 二、解决办法 首先定义一个名为ListNode的类&#xff1a; class ListNode:def __init__(self, val0, nextNone):self.val valself.next nextListNode代表一个链表节点&#xff0c;每个节点包含一个值&#xff…

【python】给你女神制作一个520图片墙吧~

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 环境使用 所需软件&#xff1a; Python 3.8 解释器 Pycharm 编辑器 模块使用&#xff1a; 内置模块 import re >>> python独有的匹配字符串的模块&#xff0c;该模块种提供功能基于正则表达式实现的&#xff0c…

六级备考28天|CET-6|听力第一讲|基本做题步骤与方法|13:30~14:30

目录 1. 重点词汇 proofread / ˈpruːfriːd / v.校对&#xff0c;校阅 autonomous adj.独立的 obsession n. 喜好 ample …

网络安全的学习路线

在众多高大上的学习路线指导中&#xff0c;尝试做一股清流&#xff0c;把要讲清楚的都讲清楚&#xff0c;该学些什么&#xff0c;学到哪个程度进入到下一阶段的学习这些才是最重要的。 在学习之前首先要做好学习的系统规划&#xff1a; 1.目前市场需求主流的岗位里&#xff0…

vue3+ts+wangEditor5菜单栏添加自定义图标按钮,自定义弹出界面内容,自定义插入链接 五步走

Wangeditor安装&#xff1a;VUE3的安装 &#xff0c;其它看官网&#xff1a; npm install wangeditor/editor --save npm install wangeditor/editor-for-vuenext --save 官网&#xff1a;优势 | wangEditor 官方插入自定义内容样例&#xff1a; https://github.com/wange…

XDP入门体验之hello world

本文目录 1、下面这二张图&#xff0c;能非常好的说明XDP在Linux内核里的网络数据处理架构上的位置。2、XDP提供了可编程的灵活处理方式&#xff0c;XDP 程序可以通过 XDP action code来指定驱动程序对报文的后续处理方式&#xff1a;3、一个将收到的报文在XDP里直接丢弃的例子…

一款IP合并和分解工具

一&#xff1a;需求说明 近期在工作中有个需求&#xff0c;需要将七千多个ip地址&#xff08;有的带掩码&#xff0c;有的不带掩码&#xff09;进行合并尝试&#xff0c;看能不能通过合并减少ip的条目数。这就涉及到ip和掩码的计算&#xff0c;举例如下: 192.168.1.0/25 192.16…

第四章 matlab的循环结构

循环(loop)是一种 matlab 结构,它允许我们多次执行一系列的语句。循环结构有两种 基本形式:while 循环和 for 循环。两者之间的最大不同在于代码的重复是如何控制的。在 while 循环中,代码的重复的次数是不能确定的,只要满足用户定义的条件,重复就进行下 去。相对地,在 fo…