詳解Java數(shù)組的四種拷貝方式
深拷貝與淺拷貝的區(qū)別
假設(shè)現(xiàn)在有原數(shù)組A以及拷貝后的數(shù)組B,若是改變A中的某一個(gè)值,B數(shù)組隨之相應(yīng)的發(fā)生變化的拷貝方式稱(chēng)為淺拷貝,反之B數(shù)組不受影響,則稱(chēng)為深拷貝;
簡(jiǎn)單總結(jié)一下兩者的概念:
深拷貝:拷貝后,修改原數(shù)組,不會(huì)影響到新數(shù)組;
淺拷貝:拷貝后,修改原數(shù)組,新數(shù)組也會(huì)相應(yīng)的發(fā)生改變;
1. for循環(huán)進(jìn)行拷貝
拷貝數(shù)值類(lèi)型
當(dāng)數(shù)組中存放的元素為基本數(shù)據(jù)類(lèi)型時(shí),此時(shí)發(fā)生的是深拷貝;
//1. for循環(huán)拷貝 (拷貝數(shù)值類(lèi)型) ---深拷貝 public static void main(String[] args) { int[] A = {1,2,3,4,5}; int[] B = new int[A.length]; for (int i = 0; i < A.length; i++) { B[i] = A[i]; } System.out.println("A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println("===========修改后==========="); A[0] = 100; System.out.println("A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] } //打印對(duì)象數(shù)組的方法 public static void show(Num[] arrays) { for (int i = 0; i < arrays.length; i++) { System.out.print(arrays[i].getVal() + " "); } System.out.println(); } class Num{ public int val = 0; public Num(int val) { this.val = val; } public int getVal() { return val; } public void setVal(int val) { this.val = val; } }
拷貝引用類(lèi)型
當(dāng)數(shù)組中存放的元素為引用數(shù)據(jù)類(lèi)型時(shí),此時(shí)發(fā)生的是淺拷貝;
//1. for循環(huán)拷貝 (拷貝引用數(shù)據(jù)類(lèi)型) ---淺拷貝 public static void main(String[] args) { Num[] A = new Num[4]; A[0] = new Num(1); A[1] = new Num(2); A[2] = new Num(3); A[3] = new Num(4); Num[] B = new Num[4]; for (int i = 0; i < A.length; i++) { B[i] = A[i]; } show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println("===========修改后==========="); A[0].setVal(100); show(A); //100 2 3 4 show(B); //100 2 3 4 }
2. copyof / copyOfRange
拷貝數(shù)值類(lèi)型
當(dāng)數(shù)組中存放的元素為基本數(shù)據(jù)類(lèi)型時(shí),此時(shí)發(fā)生的是深拷貝;
Arrays.copy(原數(shù)組,自定義新數(shù)組長(zhǎng)度);
Arrays.copyOfRange(原數(shù)組,from,to);
注意拷貝截取的范圍是左閉右開(kāi)的[from,to)
//2. copy / copyOfRange (拷貝數(shù)值類(lèi)型) ---深拷貝 public static void main(String[] args) { int[] A = {1,2,3,4,5}; int[] B = Arrays.copyOf(A,A.length); int[] C = Arrays.copyOfRange(A,1,3); System.out.println("A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println("C : " + Arrays.toString(C)); //C : [2, 3] System.out.println("===========修改后==========="); A[0] = 100; System.out.println("A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println("C : " + Arrays.toString(C)); //C : [2, 3] }
拷貝引用類(lèi)型
當(dāng)數(shù)組中存放的元素為類(lèi)的對(duì)象時(shí),此時(shí)發(fā)生的是淺拷貝;
//2. copy / copyOfRange (拷貝引用類(lèi)型) ---淺拷貝 public static void main(String[] args) { Num[] A = new Num[4]; A[0] = new Num(1); A[1] = new Num(2); A[2] = new Num(3); A[3] = new Num(4); Num[] B = Arrays.copyOf(A,A.length); show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println("===========修改后==========="); A[0].setVal(100); show(A); //100 2 3 4 show(B); //100 2 3 4 } class Num{ public int val = 0; public Num(int val) { this.val = val; } public int getVal() { return val; } public void setVal(int val) { this.val = val; } }
3. arraycopy
拷貝數(shù)值類(lèi)型
當(dāng)數(shù)組中存放的元素為基本數(shù)據(jù)類(lèi)型時(shí),此時(shí)發(fā)生的是深拷貝;
System.arraycopy(src, srcPos dest, destPos, length);
其中各個(gè)參數(shù)分別表示 如下:
- src :源數(shù)組
- srcPos:源數(shù)組要復(fù)制的起始位置
- dest:目標(biāo)數(shù)組
- destPos:目標(biāo)數(shù)組復(fù)制的起始位置
- length:復(fù)制的長(zhǎng)度
所以srcPos和destPos都為0,且length為源數(shù)組長(zhǎng)度時(shí),表示完完整整的拷貝過(guò)來(lái)了;那么截取范圍拷貝也舉個(gè)例子,下面的代碼中srcPos = 1,destPos = 2,length = 2,表示從A數(shù)組下標(biāo)為1的位置開(kāi)始截取2個(gè)元素,放到B數(shù)組中下標(biāo)為2的位置作為起始位置,再對(duì)比一下輸出看看。
//3. arraycopy (拷貝數(shù)值類(lèi)型) ---深拷貝 public static void main(String[] args) { int[] A = {1,2,3,4,5}; int[] B = new int[A.length]; //System.arraycopy(A,0,B,0,A.length); System.arraycopy(A,1,B,2,2); System.out.println("A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [0, 0, 2, 3, 0] System.out.println("===========修改后==========="); A[0] = 100; System.out.println("A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [0, 0, 2, 3, 0] }
拷貝引用類(lèi)型
當(dāng)數(shù)組中存放的元素為類(lèi)的對(duì)象時(shí),此時(shí)發(fā)生的是淺拷貝;
//3. arraycopy (拷貝引用類(lèi)型) ---淺拷貝 public static void main(String[] args) { Num[] A = new Num[4]; A[0] = new Num(1); A[1] = new Num(2); A[2] = new Num(3); A[3] = new Num(4); Num[] B = new Num[4]; System.arraycopy(A,0,B,0,A.length); show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println("===========修改后==========="); A[0].setVal(100); show(A); //100 2 3 4 show(B); //100 2 3 4 } class Num{ public int val = 0; public Num(int val) { this.val = val; } public int getVal() { return val; } public void setVal(int val) { this.val = val; } }
4. clone
拷貝數(shù)值類(lèi)型
當(dāng)數(shù)組中存放的元素為基本數(shù)據(jù)類(lèi)型時(shí),此時(shí)發(fā)生的是深拷貝;
//4. clone (拷貝數(shù)值類(lèi)型) ---深拷貝 public static void main(String[] args) { int[] A = {1,2,3,4,5}; int[] B = A.clone(); System.out.println("A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println("===========修改后==========="); A[0] = 100; System.out.println("A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println("B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] }
拷貝引用類(lèi)型
當(dāng)數(shù)組中存放的元素為類(lèi)的對(duì)象時(shí),此時(shí)發(fā)生的是淺拷貝;
//4. clone (拷貝引用類(lèi)型) ---淺拷貝 public static void main(String[] args) { Num[] A = new Num[4]; A[0] = new Num(1); A[1] = new Num(2); A[2] = new Num(3); A[3] = new Num(4); Num[] B = A.clone(); show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println("===========修改后==========="); A[0].setVal(100); show(A); //100 2 3 4 show(B); //100 2 3 4 }
5. 總結(jié)
拷貝方式 | 數(shù)值類(lèi)型 | 引用類(lèi)型 | 推薦使用 |
---|---|---|---|
for循環(huán) | 深拷貝 | 淺拷貝 | |
copyof | 深拷貝 | 淺拷貝 | √ |
arraycopy | 深拷貝 | 淺拷貝 | √ |
clone | 深拷貝 | 淺拷貝 |
由于arraycopy底層是C++寫(xiě)的,所以速度快,更多的是使用這個(gè)方法。
注意:本文中所有的引用數(shù)據(jù)類(lèi)型都是以類(lèi)的對(duì)象為例,使用的是對(duì)象數(shù)組,我們也知道引用類(lèi)型包括類(lèi),接口,字符串等等。但是需要注意字符串是新的變量,所以如果是連個(gè)字符串?dāng)?shù)組進(jìn)行拷貝,即使他們是引用類(lèi)型,但是每次都會(huì)創(chuàng)建了一個(gè)字符串?dāng)?shù)組對(duì)象, 因此, 修改原數(shù)組, 不會(huì)影響到新數(shù)組,即深拷貝。
以上就是詳解Java數(shù)組的四種拷貝方式的詳細(xì)內(nèi)容,更多關(guān)于Java數(shù)組拷貝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用Mybatis的Batch?Insert?Support?實(shí)現(xiàn)批量插入
這篇文章主要介紹了使用Mybatis的Batch?Insert?Support?實(shí)現(xiàn)批量插入。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07java 通過(guò) SmbFile 類(lèi)操作共享文件夾的示例
這篇文章主要介紹了java 通過(guò) SmbFile 類(lèi)操作共享文件夾,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02Spring Cloud引入Eureka組件,完善服務(wù)治理
這篇文章主要介紹了Spring Cloud引入Eureka組件,完善服務(wù)治理的過(guò)程詳解,幫助大家更好的理解和使用spring cloud,感興趣的朋友可以了解下2021-02-02Java在長(zhǎng)字符串中查找短字符串的實(shí)現(xiàn)多種方法
這篇文章主要介紹了Java在長(zhǎng)字符串中查找短字符串的實(shí)現(xiàn)多種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12詳解Java中ThreadLocal類(lèi)型及簡(jiǎn)單用法
ThreadLocal實(shí)例通常是希望將狀態(tài)與線程關(guān)聯(lián)起來(lái)的類(lèi)中的私有靜態(tài)字段,下面通過(guò)例子給大家詳細(xì)介紹Java中ThreadLocal類(lèi)型及簡(jiǎn)單用法,感興趣的朋友跟隨小編一起看看吧2021-10-10解決SpringBoot加載application.properties配置文件的坑
這篇文章主要介紹了SpringBoot加載application.properties配置文件的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Feign Client 超時(shí)時(shí)間配置不生效的解決
這篇文章主要介紹了Feign Client 超時(shí)時(shí)間配置不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09