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

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

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[],所以不能合并两个以上的数组。望各位引以为戒。

参考:https://www.jb51.net/article/129962.htm

以上所述是小编给大家介绍的Java合并数组的两种实现方式详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Java实现把两个数组合并为一个的方法总结

    本文实例讲述了Java实现把两个数组合并为一个的方法.分享给大家供大家参考,具体如下: 在Java中,如何把两个String[]合并为一个? 看起来是一个很简单的问题.但是如何才能把代码写得高效简洁,却还是值得思考的.这里介绍四种方法,请参考选用. 一.apache-commons 这是最简单的办法.在apache-commons中,有一个ArrayUtils.addAll(Object[], Object[])方法,可以让我们一行搞定: String[] both = (String[]) A

  • 浅谈JAVA实现选择排序,插入排序,冒泡排序,以及两个有序数组的合并

    一直到大四才开始写自己的第一篇博客,说来实在有点羞愧.今天写了关于排序的算法题,有插入排序,冒泡排序,选择排序,以下贴上用JAVA实现的代码: public class test5 { public static void print(int []array) //输出数组方法 { for(int i=0;i<array.length;i++) System.out.print(" "+array[i]); } public static void selectsort(int

  • java 两个数组合并的几种方法

    本文介绍了java 两个数组合并的几种方法,分享给大家,也给自己留个笔记 需求:两个字符串合并(如果想去重复,参考下一篇--数组去重复及记录重复个数) //方法一 Arrays类 String[] a = {"A","B","C"}; String[] b = {"D","E"}; // List<String> list = Arrays.asList(a); --OK // List<

  • java解一个比较特殊的数组合并题

    给定两个排序后的数组A和B,其中A的末端有足够的空间容纳B,编写一个方法将B合并到A并排序. 拿到这个题后,最直接的想法就是比较A和B中的元素,并按顺序插入数组,直到遍历完A和B中的所有元素.但是这样做会有一个不好的地方:如果元素的插入位置在数组A的前端,那就必须将原来的数组往后移动.这会增加开销.但是我们可以使用另外的一种办法将元素插入数组A的末端.这样我们不会出现元素移动的情况!代码如下:     复制代码 代码如下: /*  * lastA:a中的实际元素数  lastB:b中的实际元素数

  • 合并有序数组的实现(java与C语言)

    合并有序数组的实现 java版本: 实例代码 public class Merge { //合并有序数组 public static void mergeSort(int a[], int b[], int c[]) { int n = a.length, m = b.length; int i, j, k; i = j = k = 0; while (i < n && j < m) { if (a[i] < b[j]) { c[k++] = a[i++]; } else

  • java实现把两个有序数组合并到一个数组的实例

    如下所示: package com.test.sort; public class testMerge { public static void main(String[] args) { int[] a = { 1, 3, 5 }; int[] b = { 2, 3, 4, 7 }; merge m = new merge(); m.method(a, b); } } class merge { public void method(int[] a, int[] b) { int l = a.

  • java中两个byte数组实现合并的示例

    今天在于硬件进行交互的过程中,要到了了需要两个数组进行合并,然后对数组进行反转和加密操作,以下是两个byte数组合并的方法. /** * * @param data1 * @param data2 * @return data1 与 data2拼接的结果 */ public static byte[] addBytes(byte[] data1, byte[] data2) { byte[] data3 = new byte[data1.length + data2.length]; Syste

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

    最近在写代码时遇到了需要合并两个数组的需求,突然发现以前没用过,于是研究了一下合并数组的方式,总结如下. 1.System.arraycopy()方法 (1) 解析 通过阅读JDK源码,我可以知道方法原型如下: public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 其中: src是源数组 srcPos是源数组复制的起始位置 dest是目标数组 destP

  • 详解java Collections.sort的两种用法

    Collections是一个工具类,sort是其中的静态方法,是用来对List类型进行排序的,它有两种参数形式: public static <T extends Comparable<? super T>> void sort(List<T> list) { list.sort(null); } public static <T> void sort(List<T> list, Comparator<? super T> c) {

  • 详解Nginx 和 PHP 的两种部署方式的对比

    详解Nginx 和 PHP 的两种部署方式的对比 2种部署方式简介 第一种 前置1台nginx服务器做HTTP反向代理和负载均衡 后面N太服务器的Nginx做Web服务,并调用php-fpm提供的fast cgi服务 此种部署方式最为常见,web服务和PHP服务在同一台服务器上都有部署 第二种 前置1台nginx服务器做Web服务 后面服务器只部署php-fpm服务,供nginx服务器调用 前置1台nginx服务器,在调用后面多例php-fpm服务时,也可以做到负载均衡 如下图 : 对比 从系统

  • 详解Java创建线程的五种常见方式

    目录 Java中如何创建线程呢? 1.显示继承Thread,重写run来指定现成的执行代码. 2.匿名内部类继承Thread,重写run来执行线程执行的代码. 3.显示实现Runnable接口,重写run方法. 4.匿名内部类实现Runnable接口,重写run方法 5.通过lambda表达式来描述线程执行的代码 [面试题]:Thread的run和start之间的区别? Thread类的具体用法 Thread类常见的一些属性 中断一个线程 1.方法一:让线程run完 2.方法二:调用interr

  • 详解springboot集成websocket的两种实现方式

    WebSocket跟常规的http协议的区别和优缺点这里大概描述一下 一.websocket与http http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要有三次握手才能发送信息.http链接分为短链接,长链接,短链接是每次请求都要三次握手才能发送自己的信息.即每一个request对应一个response.长链接是在一定的期限内保持链接.保持TCP连接不断开.客户端与服务器通信,必须要有客户端发起然后服务器返回结果.客户端是主动的,服务器是被动的.  WebSock

  • 详解java动态代理的2种实现方式

    java的动态代理在接java的api上有说明,这里就不写了.我理解的代理: 对特定接口中特定方法的功能进行扩展,这就是代理.代理是通过代理实例关联的调用处理程序对象调用方法. 下面通过一个例子看一下: 接口: public interface Num { void show(); int getNum(); int getProduct(int x); } 实现类: public class MyNum implements Num { @Override public int getNum(

  • 详解Android中Fragment的两种创建方式

    fragment是Activity中用户界面的一个行为或者是一部分.你可以在一个单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再使用.你可以认为fragment是activity的一个模块零件,它有自己的生命周期,接收它自己的输入事件,并且可以在Activity运行时添加或者删除. 两个概念:Fragment.宿主 fragment的生命周期直接受其宿主activity的生命周期的影响.例如,一旦activity被暂停,它里面所有的fra

  • 详解springboot之jackson的两种配置方式

    springboot 针对jackson是自动化配置的,如果需要修改,有两种方式: 方式一:通过application.yml 配置属性说明:## spring.jackson.date-format指定日期格式,比如yyyy-MM-dd HH:mm:ss,或者具体的格式化类的全限定名 spring.jackson.deserialization是否开启Jackson的反序列化 spring.jackson.generator是否开启json的generators. spring.jackson

  • 详解Java中数组判断元素存在几种方式比较

    1. 通过将数组转换成List,然后使用List中的contains进行判断其是否存在 public static boolean useList(String[] arr,String containValue){ return Arrays.asList(arr).contains(containValue); } 需要注意的是Arrays.asList这个方法中转换的List并不是java.util.ArrayList而是java.util.Arrays.ArrayList,其中java.

  • Java动态代理的两种实现方式详解【附相关jar文件下载】

    本文实例讲述了Java动态代理的两种实现方式.分享给大家供大家参考,具体如下: 一说到动态代理,我们第一个想到肯定是大名鼎鼎的Spring AOP了.在AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理.两种方法同时存在,各有优劣.jdk动态代理是由java内部的反射机制来实现的,cglib动态代理是通过继承来实现的,底层则是借助asm(Java 字节码操控框架)来实现的(采用字节码的方式,给A类创建一个子类B,子类B使用方法拦截的技术拦截所以父类的方法调用)

随机推荐