文档章节

java 中数组拷贝详细介绍(arraycopy,addAll,序列化和反序列化)

开源中国首席----
 开源中国首席----
发布于 2014/05/23 14:48
字数 1064
阅读 84
收藏 0

一、场景

有时候由于需要可能需要拷贝数组的中的数据,从而是我们能更好的操作数据

二、使用方法

在这个时候我们一般会想到数组的拷贝的方式,当然这种方式可以使用,一般有addALL,和System.arraycopy。但一定要注意你的数组中放的是什么数据,是对象还是基本类型的数据。这一点很重要,接下来将通过测试代码详细介绍这些方法。

1、addAll()和System.arraycopy的区别:

以下是java底层对addAll实现的方法。可以看到实际上是调用了System.arraycopy

public boolean addAll(int index, Collection<? extends E> c) {

if (index > size || index < 0)

throw new IndexOutOfBoundsException(

"Index: " + index + ", Size: " + size);

Object[] a = c.toArray();

int numNew = a.length;

ensureCapacity(size + numNew);  // Increments modCount

int numMoved = size - index;

if (numMoved > 0)

System.arraycopy(elementData, index, elementData, index + numNew,

numMoved);

System.arraycopy(a, 0, elementData, index, numNew);

size += numNew;

return numNew != 0;

}

 2、测试放入基本数据类型,和对象之间的区别
public class TestArrayCopy {

public static void main(String[] args) {   

Student[] s = {new Student(18,"Lucy"),new Student(20,"Lily")};   

Student[] sBak = new Student[2];   


//arraycopy(Object src, int srcStartIndex, Object dest, int destStartIndex, int length) 

//从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。 

//srcStartIndex:原数组中要开始复制的第一个元素的位置 

//destStartIndex: 目标数组中要开始替换的第一个元素的位置 

//length: 要复制的元素的个数

System.out.println("没修改前");   

for(int i=0; i<s.length; i++) {   

System.out.println(sBak[i] + "\t");   

}   

System.arraycopy(s,0,sBak,0,s.length);

System.out.println("------------------拷贝后----");

for(int i=0; i<s.length; i++) {   

System.out.println(sBak[i] + "\t");   

}   

System.out.println();   

System.out.println("------------------------------------");   

System.out.println("修改后输出原数组");   

s[0].setAge(8888);   

s[0].setName("MicXP.com"); //这里改的是sBak[0]引用的对像的值。  

//sBak[0]=new Student(88,"MicXP"); //这里是直接改sBak[0]引用地址。  

for(int i=0; i<s.length; i++) {   

System.out.println(s[i] + "\t");   

}   


System.out.println();   

System.out.println("------------------------------------");   

System.out.println("修改后输出拷贝的数组");    

for(int i=0; i<s.length; i++) {   

System.out.println(sBak[i] + "\t");   

}   

}   

}   

class Student {   

private int age ;   

private String name ;   

Student(int age, String name) {   

this.age = age;   

this.name = name;   

}    

public void setAge(int age) {   

this.age = age;   

}   

public int getAge() {   

return age;   

}   

public void setName(String name) {   

this.name = name;   

}   

public String getName() {   

return name;   

}   

@Override

public String toString() {   

return "姓名:"+ this.name +"\t"+"年龄:"+this.age;   

}   

}

从以上输出结果可以看出,当我们修改了源数组中的对象,会影响目标数组的对象数据。所以这种拷贝方式是不靠谱的,并没有真正将数据进行复制。

下面是测试基本数据类型的代码。


public class TestArr {

public static void main(String[] args) {

// TODO Auto-generated method stub

int a[] = {1,2,3,4};

int b[] = {2,3,4,5};

System.arraycopy(a,0,b,0,a.length);

System.out.println("---------拷贝后-----" );

System.out.println("a---------->");

for(int i=0;i<a.length;i++){

System.out.print(a[i]+",");

}

System.out.println();

System.out.println("b---------->");

for(int i=0;i<b.length;i++){

System.out.print(b[i]+",");

}

a[3] = 45;

System.out.println();

System.out.println("--------修改原数组");

System.out.println("a---------->");

for(int i=0;i<a.length;i++){

System.out.print(a[i]+",");

}

System.out.println();

System.out.println("b---------->");

for(int i=0;i<b.length;i++){

System.out.print(b[i]+",");

}

}

}

&#160;

从以上数据结果可以看出,当我们拷贝数据后,修改源数组数据,不影响目标数组数据。

所以再数组拷贝的时候要注意这些问题,如果是对象则是拷贝引用。如果是基本数据类型,则拷贝的是真正的数据。

三、疑问

&#160;&#160;&#160;&#160;&#160;&#160;&#160; 有什么比较高效的真正拷贝数据的方法?clone?for循环再重新构造?如果你知道你通过评论告诉我,谢谢。

四、疑问的答案

 1、序列化和反序列化

序列化和反序列化的定义:把Java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。

2、序列化和反序列化的应用场景

 永久性保存对象,保存对象的字节序列到本地文件中

通过序列化在网络中传递对象

通过序列化在进程间传递对象

3、可以通过对象的序列化和反序列化来进行对象的深度拷贝

(数组中的对象需要implements Serializable)

public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {  

ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  

ObjectOutputStream out = new ObjectOutputStream(byteOut);  

out.writeObject(src);  


ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  

ObjectInputStream in = new ObjectInputStream(byteIn);  

@SuppressWarnings("unchecked")  

List<T> dest = (List<T>) in.readObject();  

return dest;  

}

© 著作权归作者所有

开源中国首席----
粉丝 6
博文 44
码字总数 38812
作品 0
西安
私信 提问
xson 1.0.2 发布,增加 byte[] buffer,支持 XCO

xson 1.0.2 已发布,新版增加了 byte[] buffer,支持 XCO。 新版本特性 新增buffer包,此包中的相关类提供对序列化过程中的byte[]进行分配、使用、回收的管理;进一步提供序列化的速度,并减...

xson_org
2017/07/31
756
0
源码之ArrayList和Vector

父类介绍 说明: 继承AbstractList,实现List接口,提供了add、remove、indexOf、get等相关方法 实现RandomAccess接口,提供了随机访问功能。在ArrayList中,我们即可以通过元素的序号快速获...

yimingkeji
01/06
24
0
Java基础知识之ArrayList知识点总结

本文包含常见的ArrayList的基本知识。在一些主题下也自然地引出了Colletion类的一些相关知识。 一.ArrayList的底层数据结构 ArrayList底层是使用一个Object[]数组来存储数据的,所以它本质上...

第四单元
01/11
0
0
Android Serializable与Parcelable原理与区别

一、序列化、反序列化是什么? (1) 名词解释 对象的序列化 : 把Java对象转换为字节序列并存储至一个储存媒介的过程。 对象的反序列化:把字节序列恢复为Java对象的过程。 (2) 序列化详细解释 ...

KingMing
2015/04/16
232
0
集合类学习之Arraylist 源码分析

1.概述 ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。 ...

Kerry_Han
2014/08/01
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
今天
3
0
数据库中间件MyCat

什么是MyCat? 查看官网的介绍是这样说的 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务、ACID、可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵...

沉浮_
今天
4
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
今天
6
0
常用物流快递单号查询接口种类及对接方法

目前快递查询接口有两种方式可以对接,一是和顺丰、圆通、中通、天天、韵达、德邦这些快递公司一一对接接口,二是和快递鸟这样第三方集成接口一次性对接多家常用快递。第一种耗费时间长,但是...

程序的小猿
今天
5
0
Python机器学习之数据探索可视化库yellowbrick

背景介绍 从学sklearn时,除了算法的坎要过,还得学习matplotlib可视化,对我的实践应用而言,可视化更重要一些,然而matplotlib的易用性和美观性确实不敢恭维。陆续使用过plotly、seaborn,...

yeayee
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部