java 中數組拷貝詳細介紹(arraycopy,addAll,序列化和反序列化)

1、場景

有時候因爲須要可能須要拷貝數組的中的數據,從而是咱們能更好的操做數據java

2、使用方法

在這個時候咱們通常會想到數組的拷貝的方式,固然這種方式可使用,通常有addALL,和System.arraycopy。但必定要注意你的數組中放的是什麼數據,是對象仍是基本類型的數據。這一點很重要,接下來將經過測試代碼詳細介紹這些方法。數組

一、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;

}

 二、測試放入基本數據類型,和對象之間的區別
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;   

}   

}

從以上輸出結果能夠看出,當咱們修改了源數組中的對象,會影響目標數組的對象數據。因此這種拷貝方式是不靠譜的,並無真正將數據進行復制。ide

下面是測試基本數據類型的代碼。測試


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;this

從以上數據結果能夠看出,當咱們拷貝數據後,修改源數組數據,不影響目標數組數據。spa

因此再數組拷貝的時候要注意這些問題,若是是對象則是拷貝引用。若是是基本數據類型,則拷貝的是真正的數據。code

3、疑問

&#160;&#160;&#160;&#160;&#160;&#160;&#160; 有什麼比較高效的真正拷貝數據的方法?clone?for循環再從新構造?若是你知道你經過評論告訴我,謝謝。對象

4、疑問的答案

 一、序列化和反序列化

序列化和反序列化的定義:把Java對象轉換爲字節序列的過程稱爲對象的序列化。把字節序列恢復爲Java對象的過程稱爲對象的反序列化。進程

二、序列化和反序列化的應用場景

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

經過序列化在網絡中傳遞對象

經過序列化在進程間傳遞對象

三、能夠經過對象的序列化和反序列化來進行對象的深度拷貝

(數組中的對象須要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;  

}
相關文章
相關標籤/搜索