首页 > 编程语言 >深入解析Java中的数组复制:System.arraycopy、Arrays.copyOf和Arrays.copyOfRange

深入解析Java中的数组复制:System.arraycopy、Arrays.copyOf和Arrays.copyOfRange

时间:2023-09-10 13:03:31浏览次数:48  
标签:Java copyOf newLength Arrays Object System 数组 newType

当涉及到在Java中处理数组时,有许多方法可供选择,其中一些包括System.arraycopy()Arrays.copyOf()Arrays.copyOfRange()。这些方法允许您在不同的数组之间复制数据,但它们之间有一些细微的差异。在本篇博客文章中,我们将深入探讨这些方法,以便您了解何时使用它们以及如何正确使用它们。

System.arraycopy()

System.arraycopy方法是Java中的本地方法,其实际实现是由Java虚拟机的底层实现提供的。

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

参数说明:

  • src:源数组
  • srcPos:源数组中的起始位置
  • dest:目标数组
  • destPos:目标数组中的起始位置
  • length:要复制的元素个数

System.arraycopy()方法的性能非常高,因为它是由底层代码实现的,并且能够利用硬件的特性来进行快速的数据复制。它通常比使用循环逐个复制数组元素要快得多。

System.arraycopy() 可以用于向上或向下转型,但在使用时要谨慎,确保数据类型兼容性和运行时类型检查。如果数据类型不匹配,虽然可通过编译,但运行时会跑出运行时异常java.lang.ArrayStoreException。最好的做法是尽量避免不必要的类型转换,以保持代码的清晰性和可维护性。

示例:

public static void main(String[] args) {

    String[] strArray = new String[]{"xj1","xj2","xj3","xj4","xj5"};
    String[] strArrayCopy = new String[5];
    System.arraycopy(strArray,0,strArrayCopy,0,3);

    //向下转型
    TestEntity[] testArray = new TestChildEntity[]{new TestChildEntity("xiuji","xj")} ;
    TestChildEntity[] testChildArrayCopy = new TestChildEntity[2];

    System.arraycopy(testArray,0,testChildArrayCopy,0,1);

    System.out.println(Arrays.toString(strArrayCopy));
    System.out.println(Arrays.toString(testChildArrayCopy));
}

运行结果

[xj1, xj2, xj3, null, null]
[TestChildEntity{nickName='xj'name='xiuji'}, null]

Arrays.copyOf()

语法:

不转换类型

copyOf(T[] original, int newLength)

转换类型

copyOf(U[] original, int newLength, Class<? extends T[]> newType)

参数说明:

  • original:要复制的原始数组。
  • newLength:新数组的长度,它可以比原始数组的长度长或短。
  • newType:新数组的类型,是一个Class对象,通常是一个数组类。它用于确定新数组的类型。

源码:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
     
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);这是一个三元条件运算符,
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
  • @SuppressWarnings("unchecked"):这个注解,用于告诉编译器忽略未经检查的转换警告。因为在这个方法中进行了类型转换,所以使用这个注解来抑制警告。
  • T[] copy = ((Object)newType == (Object)Object[].class): 这个三元条件运算符,它根据newType的类型创建一个新的数组copy。如果newType是Object[].class,则创建一个Object类型的新数组;否则,使用Array.newInstance()方法创建一个新数组,其类型由newType的组件类型确定。
  • System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength)): System.arraycopy()方法用于将原始数组的元素复制到新数组中。它的参数包括原始数组、原始数组的起始位置(0表示从第一个元素开始)、目标数组(即新数组)、目标数组的起始位置(0表示从第一个位置开始复制),以及要复制的元素数量,数量由原始数组长度和newLength中较小的那个确定。

示例:

public static void main(String[] args) {

    String[] strArray = new String[]{"xj1","xj2","xj3","xj4","xj5"};
    String[] strArrayCopy = Arrays.copyOf(strArray,8);

    //向下转型
    TestEntity[] testArray = new TestChildEntity[]{new TestChildEntity("xiuji","xj")} ;
    TestChildEntity[] testChildArrayCopy =Arrays.copyOf(testArray,3,TestChildEntity[].class);

    System.out.println(Arrays.toString(strArrayCopy));
    System.out.println(Arrays.toString(testChildArrayCopy));

}

运行结果:

[xj1, xj2, xj3, xj4, xj5, null, null, null]
[TestChildEntity{nickName='xj'name='xiuji'}, null, null]

Arrays.copyOfRange()

语法:

不转换类型

copyOfRange(U[] original, int from, int toe)

转换类型

copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType)
  • original:这是要复制元素的原始数组。
  • from:这是要复制的范围的起始索引。
  • to:这是要复制的范围的结束索引(不包括在内)。
  • newType:这是新数组的类型,通常是一个数组类。

源码:

public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
    int newLength = to - from;
    if (newLength < 0)
        throw new IllegalArgumentException(from + " > " + to);
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, from, copy, 0,
                     Math.min(original.length - from, newLength));
    return copy;
}
  • int newLength = to - from;:此行计算新数组的长度,基于指定的from和to索引。
  • if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);:此行检查newLength是否为负数(即from是否大于to)。如果满足此条件,它将抛出IllegalArgumentException,指示from索引大于to索引。
  • @SuppressWarnings("unchecked"):此注解用于抑制未检查的类型转换警告。
  • T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength);: 此行根据指定的newType创建一个新数组copy。它使用反射来创建所需类型的数组。 如果newType等于Object[].class,则创建一个新的Object数组,其长度为newLength。 否则,它使用Array.newInstance创建一个新的数组,该数组的组件类型与newType的组件类型相同,长度为newLength。这使您能够创建特定类型的数组。
  • System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));: 此行使用System.arraycopy执行实际的数组复制操作。它将元素从original数组的from索引开始复制到copy数组的0索引开始的位置。要复制的元素数量由Math.min(original.length - from, newLength)确定,确保仅复制指定的范围。

示例:

public static void main(String[] args) {

    String[] strArray = new String[]{"xj1","xj2","xj3","xj4","xj5"};
    String[] strArrayCopy = Arrays.copyOfRange(strArray,2,4);

    //向下转型
    TestEntity[] testArray = new TestChildEntity[]{new TestChildEntity("xiuji","xj")} ;
    TestChildEntity[] testChildArrayCopy =Arrays.copyOfRange(testArray,0,1,TestChildEntity[].class);

    System.out.println(Arrays.toString(strArrayCopy));
    System.out.println(Arrays.toString(testChildArrayCopy));

}

运行结果:

[xj3, xj4]
[TestChildEntity{nickName='xj'name='xiuji'}]

注意事项

在使用数组复制时,需要注意以下几点:

  • 如果新数组的长度小于源数组的长度,那么新数组将截取源数组的前几个元素。
  • 如果源数组中的元素是对象引用,那么新数组中的元素将仍然引用相同的对象,这意味着对新数组的修改可能会影响到源数组。
  • 如果源数组包含基本数据类型(如int、char等),新数组将包含这些基本数据类型的默认值,如0或'\0'

总结

在处理数组时,选择合适的复制方法取决于您的具体需求。以下是一些使用这些方法的一些建议:

  • 如果您需要高效的底层复制操作,并且能够手动计算起始位置和元素数量,那么System.arraycopy可能是一个不错的选择。
  • 如果您想要创建一个新数组,其长度与源数组相同,并且将源数组的内容全部复制到新数组中,那么Arrays.copyOf是一个方便的选择。
  • 如果您需要复制源数组的一部分内容到一个新数组中,那么Arrays.copyOfRange是最适合的。

不管您选择哪种方法,都可以确保在处理数组时能够更加灵活、高效和安全地进行操作。希望本文能够帮助您更好地理解和使用这些数组复制方法。

标签:Java,copyOf,newLength,Arrays,Object,System,数组,newType
From: https://blog.51cto.com/xiuji/7424497

相关文章

  • JAVAOOP
    课程目标1.【理解】什么是面向对象2.【理解】类和对象的关系3.【掌握】类的定义和使用4.【掌握】三大特征之封装5.【掌握】this关键字的使用面向对象概述什么是面向对象 Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的......
  • JVM调优篇:探索Java性能优化的必备种子面试题
    JVM内存模型首先面试官会询问你在进行JVM调优之前,是否了解JVM内存模型的基础知识。这是一个重要的入门问题。JVM内存模型主要包括程序计数器、堆、本地方法栈、Java栈和方法区(1.7之后更改为元空间,并直接使用系统内存)。正常堆内存又分为年轻代和老年代。在Java虚拟机中,年轻代用于存......
  • Java基础——变量和关键字
    变量java编程中分为变量和常量,常量是指值不能改变的量,如1,“HelloWorld”等。变量意为变化的量。可以看作是用于存放数据的一个容器。一个代词,指代它里面的那个数。如,inta=0;现在变量a的值为0,我们可以让a的值为1,a=1;通过这种赋值变量a的值变为了1。变量的定义变量类型标识符;......
  • 原生JavaScript框架设计(一):整合JS函数
    本篇为回顾js时总结,诣在整理JS中常用知识点,剖析其规律。模仿jQuery,简单一些,特定功能,像apply函数、getElementXXX函数等浏览器函数都没有实现,直接套用。创建common.js://自定义实现push函数varmyPush=function(target,els){ varj=target.length, i=0; while((target[j++]=e......
  • 在eclipse上部署Java web服务器(Tomcat)
    注意:本文章可能会具体配置实际有出入,发现错误可能是和我的版本不一致或其他问题,可以联系笔者更改或者自行斟酌。  一.配置准备1.tomcat tomcat有很多版本,eg:11.0,10.1,10.0,9.0等等 这里大家可以随意下载,但是要注意版本适配问题,我在配置是11无法再eclipse上检测,10.1能......
  • 无涯教程-JavaScript - COUPDAYBS函数
    描述COUPDAYBS函数返回从息票期限开始至结算日期的天数。语法COUPDAYBS(settlement,maturity,frequency,[basis])争论Argument描述Required/OptionalSettlement证券的结算日期。证券结算日期是指在发行日期之后将证券交易给买方的日期。RequiredMaturity证......
  • Java基础知识四
    1.数组和集合的区别数组初始化之后长度就固定了,集合不固定数组中只能存放同一种数据类型。集合中可以存放多种数组中只能存放有序的元素,可以添加重复元素。集合可以无序,不可以出现无序的元素。2.ArrayList1.7版本和1.8版本底层扩容的实现原理通过一个空参的构造器创建对象时1.7底......
  • 高级Java面试:如何在事务中使用锁?
    亲爱的小伙伴们,大家好!我是小米,很高兴再次和大家见面。今天,我将和大家分享一个关于编程中的面试题:一个有@Transaction注解的方法中有锁,需要注意什么?这个问题可能在Java后端开发的面试中常常被问到,不仅考察了对事务和锁的理解,还涉及到了多线程编程的复杂性。所以,赶快跟我一起深入探讨......
  • 小而全的Java工具类库 Hutool (扩展篇)
    配置文件(Hutool-setting)对于Properties的广泛使用使我也无能为力,有时候遇到Properties文件又想方便的读写也不容易,于是对Properties做了简单的封装,提供了方便的构造方法(与Setting一致),并提供了与Setting一致的getXXX方法来扩展Properties类,Props类继承自Properties,所以可以兼容Pr......
  • 在flink-1.17中测试执行流处理版本的单词计数程序时,出现"Exception in thread "Thread
    场景描述采用单作业模式提交作业后发现报错了 报错内容Exceptioninthread“Thread-5”java.lang.IllegalStateException:Tryingtoaccessclosedclassloader.Pleasecheckifyoustoreclassloadersdirectlyorindirectlyinstaticfields.Ifthestacktrace......