25从零开始学Java之数组扩容与数组拷贝的实现过程与原理分析

news2024/9/21 12:46:28

作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦

千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者

前言

在上一篇文章中,壹哥给大家讲解了数组的创建、初始化及遍历方式,这些是我们学习数组的基础。其实数组的内容非常多,今天这篇文章,壹哥主要带大家学习数组的扩容、缩容及拷贝,内容同样重要,希望你不要走神哦。

-------------------------------------------------前戏已做完,精彩即开始-----------------------------------------------

全文大约【3000】字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

一. 数组内存分析(重点)

1. 简介

Java的内存,可以分为栈、堆、方法区、本地方法区、程序寄存器等几个核心部分。这一块的内容,以后壹哥会专门编写文章进行介绍,对于初学者来说,这还不适合我们学习。但是我们现在要先对以下三个概念有所了解:

栈:栈中可以存储基本类型的数据和引用类型的地址。特点: 先进后出,一般空间比较小,存取速度较快。

堆:堆中可以存储引用类型的数据。特点: 空间比较大,存储速度相对较慢。

方法区:方法区中可以存储字符串常量池、静态数据、代码和类的元数据。

我们知道,数组属于引用类型,而数组的引用变量(数组名称)只是一个地址引用这个引用变量可以指向任何有效的内存空间,只有当这个引用指向有效的空间时,才可以通过引用去操作数组中真正的数据元素。所以数组的引用变量(数组名称)是存储在栈空间中,但真正的数组数据是存储在堆空间中。

2. 代码案例

为了让大家更好地理解数组的内存结构,接下来壹哥给大家设计一个代码案例,然后给大家分析一下这个数组的内存结构。

/**
 * @author 一一哥Sun 
 * QQ:2312119590 
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo01 {
	public static void main(String[] args) {
		//使用静态初始化的方式初始化一个数组a
        //a存放在栈中,a的值是数组的地址,数组的真正数据{5,7,20}存放在堆中
        int[] a = {5,7,20}; 
        System.out.println("a的长度为:" + a.length);//3

        //整型变量,存放在栈中
        int num =8;
        System.out.println("num:"+num);

        //定义一个新的数组b
        int[] b=new int[4]; 
        System.out.println("b的长度是:"+b.length);

        //将a赋值给b,是b的指向改变了,但b原先对应的数组依然存在
        b=a; 
        System.out.println("b的长度是:"+b.length);
	}
}

3. 内存分析

为了让各位更好地理解基本类型的数据和数组的内存结构,壹哥再给大家绘制下面一张图。

根据上面的代码和下面的内存分析图,我们可以得到如下结论:

  • 变量a存放在栈中,a的值是数组的首地址,数组的真正数据{5,7,20}存放在堆中;
  • 整型变量num存放在栈中;
  • 定义新的数组b,数组名称b存放在栈中,b的数据在堆中;
  • 将a赋值给b,此时b的指向改变了,但b原先对应的数组依然存在,此时b指向原先a对应的数组数据。

二. 数组扩容与缩容

1. 扩容简介

壹哥在前面给大家说过,数组一旦创建初始化后,其长度就不能被改变。但是有的小伙伴就说了,”不对啊,我看别人的文章说,可以往数组中增加很多新数据啊......“。那如果是这样,假如我们一开始定义一个长度为5的数组,然后想把10个数据元素都插进去,这能不能实现?

大家想一下,你能把10升水装到5升的瓶子中吗?肯定不行!如果你非要把10升水都装到瓶子里,肯定需要换一个新的更大的瓶子!

所以今天壹哥跟大家说的”数组扩容“,其实并不是将这些多余的数据装到原有的数组中,而是创建一个新的更大的数组,再把原有数组中的内容都复制到新数组中来!

2. 扩容与缩容流程(重点)

在Java中,数组的”扩容“和”缩容“,并不是真的改变原有数组的大小,而是创建一个新的数组,然后再进行操作,具体流程如下:

  • 步骤1:定义一个新数组,新数组的长度要比原数组增加或者减小;
  • 步骤2:将原数组中的元素拷贝到新数组中;
  • 步骤3将原数组的名称变量指向新数组。

3. 代码实现

接下来壹哥就按照上面的流程,来带大家实现一下数组的扩容和缩容。

3.1 扩容代码

以下代码是进行数组扩容的案例。

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo05 {
	public static void main(String[] args) {
		// 数组扩容
		// 原数组
		int[] oldArr = { 1, 3, 46, 22, 11 };

		// 1.定义一个新数组,长度比原数组的长度多1,用于扩容
		int[] newArr = new int[oldArr.length + 1];

		// 2.数组拷贝
		for (int i = 0; i < oldArr.length; i++) {
			//数组拷贝,将原来数组的元素拷贝到新数组中
			newArr[i] = oldArr[i];
		}

		// 3.将原数组的名称变量指向新数组
		oldArr = newArr;
		System.out.println("数组长度="+oldArr.length);
		//遍历数组
		for (int i = 0; i < oldArr.length; i++) {
			//最后一个元素的值是默认值0
			System.out.println(oldArr[i]);
		}
	}
}

这里我们使用newArr[i] = oldArr[i];这样的语句,将旧数组中的元素拷贝到新数组中

3.2 缩容代码

以下代码是进行数组缩容的案例,供大家参考:

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo06 {
	public static void main(String[] args) {
		// 数组缩容
		//定义一个原数组
		int[] oldArr = {1,3,46,22,11};

		//1.定义一个新数组,新数组的长度比原数组长度少1个
		int[] newArr = new int[oldArr.length-1];

		//2.进行数组拷贝,将旧数组中的元素拷贝到新数组中
		for (int i = 0; i < newArr.length; i++) {
			newArr[i] = oldArr[i];
		}

		//3.将原数组的名称变量指向新数组
		oldArr = newArr;
		for (int i = 0; i < newArr.length; i++) {
		    System.out.println(oldArr[i]);
		}
	}
}

三. 数组拷贝

壹哥在给大家讲解数组扩容时,涉及到了数组中数据元素的拷贝复制。那么除了上面的拷贝方式之外,数组还有哪些拷贝方式呢?

1. 拷贝方式

在Java中,数组的拷贝主要有三种实现方式:

  1. 通过循环语句,将原数组中的各个元素拷贝到新数组中(即数组扩容案例中使用的方法);
  2. System类提供的数组拷贝方法;
  3. Arrays类提供的数组拷贝方法。

接下来壹哥就设计几个案例,来给大家展示这几种方式都是怎么进行数组拷贝的。因为第一种数组拷贝方式,我们已经在数组扩容的案例中给大家演示了,这里就不再重复展示相关代码了。

2. System.arraycopy方法

2.1 简介

System.arraycopy()是Java提供的一个本地静态方法,用于将数据元素从源数组复制到目标数组。

public static native void arraycopy(Object src,int srcPos,Object dest,int destPos,int length);

arraycopy()方法有5个核心参数,其含义如下:

  • src: 源数组,即被复制的旧数组;
  • srcPos: 源数组中开始复制的索引位置;
  • dest: 目标数组,即要复制到的新数组;
  • destPos: 要复制到目标数组中的索引位置;
  • length: 要复制的元素个数。

另外我们还要注意,arraycopy()方法在有些情况下有可能会发生如下异常:

  • NullPointerException: if source or destination array is null.NullPointerException :如果源或目标数组为null时,就会产生NullPointerException异常。
  • ArrayStoreException: if the source and destination array type doesn’t match or they are not array.ArrayStoreException :如果源和目标数组类型不匹配或不是数组,会产生该异常;
  • ArrayIndexOutOfBoundsException: if the data overflow occurs because of index values or they are negative.ArrayIndexOutOfBoundsException :如果由于索引值导致数据溢出,或它们为负数时会产生该异常。

2.2 案例

我们先来看看下面这个数组拷贝的案例:

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo07 {
	public static void main(String[] args) {
		// 数组拷贝
		//1.源数组
		int[] srcArr = {1,3,46,22,11};

		//2.目标数组
		int[] destArr = new int[srcArr.length + 5];

		/**
		* src:原数组
		* srcPos:原数组的起始拷贝位置
		* dest:目标数组
		* destPos:目标数组的起始拷贝位置
		* length:拷贝的长度
		*/
		//3.调用arraycopy方法进行复制
		System.arraycopy(srcArr, 1, destArr, 3, 4);

		//对新数组进行遍历
		for (int i = 0; i < destArr.length; i++) {
		    System.out.print(destArr[i]+"\t");
		}
	}
}

3. Arrays.copyOf方法

3.1 简介

Arrays.copyOf()可以复制数组中指定范围的元素。该方法会返回一个新的数组对象,且改变新数组中的元素值,不会影响原来的数组。我们还可以利用Arrays.toString方法将赋值后的数组输出。

该方法支持的参数可以是long、float、double、int、boolean、byte、Object等类型的数组。

public static int[] copyOf(int[] original, int newLength);

copyOf()方法有2个核心参数,其含义如下:

  • original: 源数组,即被复制的旧数组;
  • newLength: 表示新数组的长度。如果新数组的长度超过源数组的长度,会采用数组元素类型的默认值。

3.2 案例

以下是Arrays.copyOf()方法的实现案例:

/**
 * @author 一一哥Sun
 * QQ:2312119590
 * CSDN、掘金、知乎找我哦
 * 千锋教育
 */
public class Demo08 {
	public static void main(String[] args) {
		// 数组拷贝
		//1.源数组
		int[] srcArr = {1,3,46,22,11};

		/**
		 * original:原数组
		 * newLength:新数组的长度
		 * 返回值:返回新数组 
		 */
		//2.调用copyOf方法进行数组拷贝
		int[] destArr = Arrays.copyOf(srcArr, srcArr.length+1);
		
		//3.遍历新数组
		for (int i = 0; i < srcArr.length; i++) {
		    System.out.print(destArr[i]+"\t");
		}
	}
}

-------------------------------------------------正片已结束,来根事后烟-----------------------------------------------

四. 结语

至此,壹哥就把数组的扩容、缩容及拷贝等内容给大家介绍完毕了,现在你明白数组的扩容原理了吗?在下一篇文章中,壹哥会继续给大家讲解数组的排序、查找等算法,内容非常重要哦,敬请继续关注吧。

另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。

五. 今日作业

1. 第一题

将班级中5个学员的名称录入到数组中,再拷贝到更大的一个数组中输出。

 

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

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

相关文章

Cookies和Session案例-注册

1. 注册功能改进 1.1 service 将之前的注册案例的代码进行优化&#xff0c;将获取sqlsession工厂对象、获取sqlsession、获取mapper等操作从servlet中分离出来转变为三层架构的形式 在service目录下创建UserService public class UserService {SqlSessionFactory sqlSessionFa…

办公室组网

1.办公网络组网中,汇聚交换机和接入交换机你会做哪些配置? 接入交换机上配置: (1)VLAN配置:由题意得办公网络中有两个部门,使用VLAN技术将每个部门划入一个局域网中,如部门1属于VLAN 10,部门2属于VLAN20.该网络中还需要额外创建一个VLAN用于管理网络,如VLAN30。在接入…

一文了解国外AIGC头部产品

AIGC是指通过人工智能技术生成的内容&#xff0c;包括文字、图片、音频和视频等。AIGC技术可以基于大量的数据和算法&#xff0c;自动地生成各种类型的内容&#xff0c;可以用于新闻报道、广告宣传、文学创作、游戏设计等各个领域。AIGC技术的优点在于可以大大提高内容生产的效…

GD32F303RCT6开发笔记(一)—— macos环境搭建

macOS vscodegccpyocd环境搭建 1、vscode/arm-none-eabi-/pyocd 安装可百度。 2、pyocd 安装完成后&#xff0c;连接st-link 输入命令后显示如下&#xff0c;说明连接成功。 3、输入命令 pyocd pack find GD32F303RC4、如果没有安装GD32F303RC包 使用命令安装 pyocd pack …

【Vue 基础】vue-cli初始化项目及相关说明

目录 1. 创建项目 2. 项目文件介绍 3. 项目的其它配置 3.1 项目运行时&#xff0c;让浏览器自动打开 3.2 关闭eslint校验功能 3.3 src文件夹简写方法 1. 创建项目 vue create 项目名 2. 项目文件介绍 创建好的项目中包含如下文件&#xff1a; &#xff08;1&#xff09…

基于显扬科技自主研发3D机器视觉HY-M5在易拉罐包装检测的应用

行业现状&#xff1a; 易拉罐包装行业发展迅速&#xff0c;是中国食品工业的重要组成部分。近年来&#xff0c;随着经济水平的提高和生活方式变化&#xff0c;各类预包装食品需求剧增&#xff0c;碳酸饮料和啤酒等饮料消费大幅增加&#xff0c;直接带动易拉罐包装行业高速发展…

方案解析丨数字人主播如何成为电商直播新标配

浙江省政府办公厅近日印发《关于进一步扩大消费促进高质量发展若干举措》支持电子商务直播发展。抢抓电子商务直播快速发展机遇&#xff0c;发展数字人虚拟主播、元宇宙新消费场景等新业态新模式。 随着电商直播快速发展&#xff0c;企业怎么高效地实现引流获客&#xff0c;成为…

【计算机组成原理】数据的表示和运算·进位计数制

&#x1f6a9; 本文已收录至专栏&#xff1a;计算机基础 我们可以通过显示屏看到各种形式的数据信息&#xff0c;但数据是如何在计算机中表示呢&#xff1f;运算器又是如何实现数据的算数、逻辑运算&#xff1f; 十进制数是最适合我们日常使用的一种计数方式&#xff0c;除此之…

随手记录:Livox 时间戳修改为ROS时间戳

参考与前言 传感器类型&#xff1a;Livox-Mid70 参考链接&#xff1a;Ubuntu20.04系统安装Livox ROS Driver 官方驱动&#xff1a;https://github.com/Livox-SDK/livox_ros_driver 碎碎念&#xff1a;之所以要改成rostime主要是 提取pcd的时候发现这个timestamp 300.xxx 打…

我那张被问爆了的漫画头像确实有点东西

不得不说&#xff0c;这个照片变漫画有点东西啊&#xff01;不知道姐妹们有没有发现❗️最近漫画人像它又火起来了&#xff0c;基本上在dy等各大社交软件上&#xff0c;特别是朋友圈已经是刷屏了&#xff5e;随便一张照片经过渲染之后秒变动漫风格照&#xff0c;我就马不停蹄就…

宝塔面板搭建自己的网站,并发布公网远程访问

文章目录 1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4.固定http地址5. 配置二级子域名6.创建一个测试页面 宝塔面板简单几步搭建本地web站点&#xff0c;并做内网穿透&#xff0c;实现公网用户也可以正常远程访问&#xff0c;无需公网IP&#xff0c;无需设置路由器。 1. 环…

这样的速度,还有谁?一个 issue 引发的性能大跃进

前段时间开源了一个关于音频特征提取和分析的小项目&#xff0c;自己是 AI 音频领域方向的&#xff0c;但受限于对音频特征的理解&#xff0c;做研究时总感觉缺乏“底料”&#xff0c;所以当做是学习练手做了这个小东西。 虽然是学习练手的小项目&#xff0c;但也信心满满&…

从盒马来看新零售的全面可行性

来源&#xff5c;新零售 不久前&#xff0c;一家位置极佳的北京老牌超市闭店的消息引发了很多人的唏嘘&#xff0c;这家超市位于北京长安街东侧的万达广场上&#xff0c;曾经作为万达广场的主力店&#xff0c;服务周边居民长达十年之久。 不过&#xff0c;周边的居民很快得知…

哪个牌子的电视盒子好用?经销商总结目前性能最好的电视盒子

做数码经销已经是第九年了&#xff0c;这些年对数码行业也算是颇有研究&#xff0c;大家选购数码产品时都会参考我的建议。今天我将来分享目前性能最好的电视盒子推荐&#xff0c;想知道哪个牌子的电视盒子好用看这篇就足够了。 一&#xff1a;泰捷WEBOX60Pro电视盒子 亮点&a…

27- OCR 光功率计数码管字符识别

要点&#xff1a; 光功率计数码管 1 前言 本案例将使用OCR技术自动识别光功率计显示屏文字&#xff0c;通过本章您可以掌握&#xff1a; PaddleOCR快速使用数据合成方法数据挖掘方法基于现有数据微调 为实现智能读数&#xff0c;通常会采取文本检测文本识别的方案&#xff…

【JavaWeb】jQuery(上)

本章内容 1.jQuery Hello world 2.jQuery 选择器 3.jQuery 过滤器 4.jQuery 元素筛选 1、jQuery 介绍 什么是 jQuery ? jQuery&#xff0c;顾名思义&#xff0c;也就是 JavaScript 和查询&#xff08;Query&#xff09;&#xff0c;它就是辅助 JavaScript 开发的 js 类…

ChatGPT能用来写小说吗-gpt可以续写小说吗

怎么用ChatGPT写网文 ChatGPT是一个语言生成模型&#xff0c;可以用于生成各种文本&#xff0c;包括网文。下面是一些写网文的建议。 确定你的主题和情节。在开始写作之前&#xff0c;你需要确保你有一个明确的主题和情节&#xff0c;这可以帮助你更好地组织你的故事&#xff0…

React18开发中遇到的一些小问题

遇到这样一个问题&#xff0c;初始化时用户登陆后需要获取到用户信息&#xff0c;但是发现获取用户信息这个接口触发了2次&#xff0c;这是不应该的&#xff0c;于是我查阅了一下资料&#xff0c;把自己的笔记记录下来。 还有就是使用mobx遇到的控制台警告问题&#xff0c;也一…

【youcans 的 OpenCV 学习课】22. Haar 级联分类器

专栏地址&#xff1a;『youcans 的图像处理学习课』 文章目录&#xff1a;『youcans 的图像处理学习课 - 总目录』 【youcans 的 OpenCV 学习课】22. Haar 级联分类器 3. Haar 特征及其加速计算3.1 Haar 特征3.2 Haar 特征值的计算3.3 积分图像3.4 基于积分图像加速计算 Haar 特…

win10系统安装虚拟机及centOS系统

win10系统安装虚拟机及centOS系统 准备工作下载软件及对应文件 安装本次虚拟机安装的版本本次centos安装的版本 问题使用虚拟机打开centos时报错&#xff1a;解决 安装成功效果 准备工作 下载软件及对应文件 虚拟机软件这里使用VMware Workstation,安装完成后需要许可证激活&…