System.arrayCopy (java 数组复制) 深入解析

2023-10-28 12:38

本文主要是介绍System.arrayCopy (java 数组复制) 深入解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

先看ArrayList源码中数组复制的代码:

其实ArrayList 就是一个数组的形式存放数据的。没有高深的地方。

他的性能在于他的索引能力,正因为他是数组形式,所以索引元素的时候他表现得非常的快速成,试想一下,只要知道这个元素的索引,E[2] 你看对像就出来了。

这就是ArrayList 最突出的地方。

让我们来看下ArrayList 内部数组是如何自我Copy的。

要想深入的了解他就必需要看他的API,add 方法与remove 方式。

看完后你就会对它有一个深刻的理解了,如下原码:

Add 方法

public void add(int index, E element) {if (index > size || index < 0)throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size);ensureCapacity(size+1); // Increments modCount!!System.arraycopy(elementData, index, elementData, index + 1, size - index);elementData[index] = element;size++;}


remove 方法

public E remove(int index) {RangeCheck(index);modCount++;E oldValue = elementData[index];int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index, numMoved);elementData[--size] = null; // Let gc do its workreturn oldValue;}


上述两个方法足以让你认识他们了。

他的主要执行过程就在于数组对像的自我复制。

System.arrayCopy这个方法是System类中的一个JNI方式实现类。

(JNI,Java Native Interface 故名思意,就是java语言调其它语言的一个接口)

这个JNI的底层在不同的平台上不一样。

打个比方windows 其实java的JNI就是调了dll。

Unix 其实就是调了.so 共享库。

做过C++的一定明白。

这个暂且放一下,让我们来关注一下arrayCopy 如何复制数组元素的。


在JAVA里面,可以用复制语句"A=B"给基本类型的数据传递值,但是如果A,B是两个同类型的数组,复制就相当于将一个数组变量的引用传递给另一个数组;

如果一个数组发生改变,那么引用同一数组的变量也要发生改变。

以下是归纳的JAVA中复制数组的方法:

1.使用FOR循环,将数组的每个元素复制或者复制指定元素,不过效率差一点

2.使用clone方法,得到数组的值,而不是引用,不能复制指定元素,灵活性差一点

3.使用System.arraycopy(src, srcPos, dest, destPos, length)方法,推荐使用

举例:

1.使用FOR循环

int[] src={1,3,5,6,7,8};int[] dest = new int[6];for(int i=0;i<6;i++) dest[i] = src[i];



2.使用clone

int[] src={1,3,5,6,7,8};int[] dest;dest=(int[]) src.clone();//使用clone创建


副本,注意clone要使用强制转换


3.使用System.arraycopy

int[] src={1,3,5,6,7,8};int[] dest = new int[6];System.arraycopy(src, 0, dest, 0, 6);


-------------------------------------------------------------------

System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制。

其函数原型是:

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

src:源数组;

srcPos:源数组要复制的起始位置;

dest:目的数组;

destPos:目的数组放置的起始位置;

length:复制的长度。

注意:src and dest都必须是同类型或者可以进行转换类型的数组。

有趣的是这个函数可以实现自己到自己复制,

比如:

int[] fun ={0,1,2,3,4,5,6};

System.arraycopy(fun,0,fun,3,3);

则结果为:{0,1,2,0,1,2,6};


JAVA提高教程-System.arraycopy方法的使用

import java.util.Arrays; public class LessionSystemArraycopy { public static void main(String[] args) { // 此方位为native方法。 // public static native void arraycopy( // Object src, int srcPos, Object dest, // int destPos, int length); // 初始化 int[] ids = { 1, 2, 3, 4, 5 }; System.out.println(Arrays.toString(ids)); // [1, 2, 3, 4, 5] // 测试自我复制 // 把从索引0开始的2个数字复制到索引为3的位置上 System.arraycopy(ids, 0, ids, 3, 2); System.out.println(Arrays.toString(ids)); // [1, 2, 3, 1, 2] // 测试复制到别的数组上 // 将数据的索引1开始的3个数据复制到目标的索引为0的位置上 int[] ids2 = new int[6]; System.arraycopy(ids, 1, ids2, 0, 3); System.out.println(Arrays.toString(ids2)); // [2, 3, 1, 0, 0, 0] // 此功能要求 // 源的起始位置+长度不能超过末尾 // 目标起始位置+长度不能超过末尾 // 且所有的参数不能为负数 try { System.arraycopy(ids, 0, ids2, 0, ids.length + 1); } catch (IndexOutOfBoundsException ex) { // 发生越界异常,数据不会改变 System.out.println("拷贝发生异常:数据越界。"); } System.out.println(Arrays.toString(ids2)); // [2, 3, 1, 0, 0, 0] // 如果是类型转换问题 Object[] o1 = { 1, 2, 3, 4.5, 6.7 }; Integer[] o2 = new Integer[5]; System.out.println(Arrays.toString(o2)); // [null, null, null, null, null] try { System.arraycopy(o1, 0, o2, 0, o1.length); } catch (ArrayStoreException ex) { // 发生存储转换,部分成功的数据会被复制过去 System.out.println("拷贝发生异常:数据转换错误,无法存储。"); } // 从结果看,前面3个可以复制的数据已经被存储了。剩下的则没有 System.out.println(Arrays.toString(o2)); // [1, 2, 3, null, null] } }


这篇关于System.arrayCopy (java 数组复制) 深入解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/293259

相关文章

PostgreSQL的扩展dict_int应用案例解析

《PostgreSQL的扩展dict_int应用案例解析》dict_int扩展为PostgreSQL提供了专业的整数文本处理能力,特别适合需要精确处理数字内容的搜索场景,本文给大家介绍PostgreS... 目录PostgreSQL的扩展dict_int一、扩展概述二、核心功能三、安装与启用四、字典配置方法

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Spring WebFlux 与 WebClient 使用指南及最佳实践

《SpringWebFlux与WebClient使用指南及最佳实践》WebClient是SpringWebFlux模块提供的非阻塞、响应式HTTP客户端,基于ProjectReactor实现,... 目录Spring WebFlux 与 WebClient 使用指南1. WebClient 概述2. 核心依

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Spring IoC 容器的使用详解(最新整理)

《SpringIoC容器的使用详解(最新整理)》文章介绍了Spring框架中的应用分层思想与IoC容器原理,通过分层解耦业务逻辑、数据访问等模块,IoC容器利用@Component注解管理Bean... 目录1. 应用分层2. IoC 的介绍3. IoC 容器的使用3.1. bean 的存储3.2. 方法注

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

java中新生代和老生代的关系说明

《java中新生代和老生代的关系说明》:本文主要介绍java中新生代和老生代的关系说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、内存区域划分新生代老年代二、对象生命周期与晋升流程三、新生代与老年代的协作机制1. 跨代引用处理2. 动态年龄判定3. 空间分

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优