欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Java合并数组的两种实现方式

程序员文章站 2024-02-24 19:58:40
最近在写代码时遇到了需要合并两个数组的需求,突然发现以前没用过,于是研究了一下合并数组的方式,总结如下。 1.system.arraycopy()方法 (1) 解析...

最近在写代码时遇到了需要合并两个数组的需求,突然发现以前没用过,于是研究了一下合并数组的方式,总结如下。

1.system.arraycopy()方法

(1) 解析

通过阅读jdk源码,我可以知道方法原型如下:

public static native void arraycopy(object src, int srcpos, object dest, int destpos, int length);

其中:
src是源数组
srcpos是源数组复制的起始位置
dest是目标数组
destpos是目标数组接收复制数据的起始位置
length是复制的长度(源数组中从复制起始位置srcpos开始需要复制的长度)

可以看到,该方法是本地方法,我们不能更深一步的了解其中的原理,但是我们可以知道其作用就是将源数组从起始位置srcpos开始将length长度的元素复制到目标数组,目标数组从destpos位置开始接收复制元素。

(2) 示例

string[] aa = {"11","22","33"};
string[] bb = {"44","55","66"};
string[] cc = {"77","88","99"};

// 合并两个数组
string[] dd = new string[aa.length + bb.length];
system.arraycopy(aa, 0, dd, 0, aa.length);
system.arraycopy(bb, 0, dd, aa.length, bb.length);

// 合并三个数组
string[] ee = new string[aa.length + bb.length + cc.length];
system.arraycopy(aa, 0, ee, 0, aa.length);
system.arraycopy(bb, 0, ee, aa.length, bb.length);
system.arraycopy(cc, 0, ee, aa.length + bb.length, cc.length);

2.arrayutils.addall()方法

(1) 解析

arrayutils工具类在apache commons-lang3-3.5中的commons-lang3-3.5.jar(jar包下载地址)中,所以使用之前需要导入这个包。通过阅读其源码,我们可以发现,其实addall()方法本质上还是调用system.arraycopy()方法。

public static <t> t[] addall(final t[] array1, final t... array2) {
   if (array1 == null) {
     return clone(array2);
   } else if (array2 == null) {
     return clone(array1);
   }
   final class<?> type1 = array1.getclass().getcomponenttype();
   @suppresswarnings("unchecked") // ok, because array is of type t
   final
   // a处
   t[] joinedarray = (t[]) array.newinstance(type1, array1.length + array2.length);
   system.arraycopy(array1, 0, joinedarray, 0, array1.length);
   try {
     // b处
     system.arraycopy(array2, 0, joinedarray, array1.length, array2.length);
   } catch (final arraystoreexception ase) {
     // check if problem was due to incompatible types
     /*
     * we do this here, rather than before the copy because:
     * - it would be a wasted check most of the time
     * - safer, in case check turns out to be too strict
     */
     final class<?> type2 = array2.getclass().getcomponenttype();
     if (!type1.isassignablefrom(type2)) {
       throw new illegalargumentexception("cannot store " + type2.getname() + " in an array of "
           + type1.getname(), ase);
     }
     throw ase; // no, so rethrow original
   }
   return joinedarray;
 }

这个方法关键的两个部分就是代码中标注的a、b两处。a处首先通过反射的方式定义了一个长度为array1、array2长度之和的数组joinedarray,然后将array1拷贝到joinedarray,b处将array2拷贝到joinedarray中。除了这两处,还有异常处理需要注意,在捕获异常后,判断了type1是不是继承于type2,也就是判断array1所对应的类型是否与array2对应类型相同,或者array1所对应的类型是否是array2对应类型的子类,否则将出现不兼容的情况。

(2) 示例

// 合并两个数组
string[] ff = arrayutils.addall(aa, bb);

// 将多个字符串合并到数组构成新数组
string[] gg = arrayutils.addall(aa, "12", "13");
string[] hh = arrayutils.addall(aa, "12", "13", "14");
string[] ii = arrayutils.addall(aa, "12", "13", "14", "15");

// 合并三个数组
string[] jj = arrayutils.addall(aa, bb);
string[] kk = arrayutils.addall(jj, cc);

需要说明的是,addall()的第二个参数是可变参数,可以传入多个相同类型的值,或者一个该类型的数组。

(3) 错误处理

我在使用过程中遇到一个问题,具体如下:
代码1:

string[] ll = arrayutils.addall(aa, bb, cc);

根据提示发现,addall()返回值类型是serializable[],所有不能喝string[]兼容。于是我将代码改成如下代码:
代码2:

arrayutils.addall(aa, bb, cc);

我以为不接收返回值只是合并就不会报错了,虽然通过了编译,但是运行还是报错了。错误信息如下:

exception in thread "main" java.lang.illegalargumentexception: cannot store java.io.serializable in an array of java.lang.string
  at org.apache.commons.lang3.arrayutils.addall(arrayutils.java:5084)
  at com.liu.date20170524.mergearrays.main(mergearrays.java:44)
caused by: java.lang.arraystoreexception
  at java.lang.system.arraycopy(native method)
  at org.apache.commons.lang3.arrayutils.addall(arrayutils.java:5073)
  ... 1 more

由于当时陷入了惯性思维,认为addall和list等的addall()方法类型,可以将多个列表(这里是数组)进行合并,所以一直没想明白错误出在哪里。后来才发现,addall()的第二个参数的类型是t,不是t[],所以不能合并两个以上的数组。望各位引以为戒。

参考:

以上所述是小编给大家介绍的java合并数组的两种实现方式详解整合,希望对大家有所帮助