Java高级篇-6-数组拷贝方法
2017-10-29 21:17
441 查看
前面我们介绍了Array和Arrays类几个常用的方法,没有提到对象clone()方法和Arrays.copyOf(),关于拷贝,放到这篇来讨论。拷贝或者复制,一般是对象的引用的操作,有三种方式来实现:直接赋值,浅拷贝,深拷贝。下面我们用代码来理解这三种情况。面试中经常拿数组的几种拷贝方法,来考察你对浅拷贝和深拷贝的理解。特别是直接赋值和对象clone这两个方法。
1.直接赋值
直接赋值很简单,例如Int a = 10, 第二行b=a,这里直接把a赋值给了b。这个时候,a和b是相等,内存地址相同,值也相等。我们用一个int基本类型的数组来举例。
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
int[] a = {40, 20, 50, 10, 60, 30};
int[] b = a;
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,100);
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
运行结果:
true
a [40, 20, 100, 10, 60, 30]
b [40, 20, 100, 10, 60, 30] 从运行结果看出:数组a和数组b确实是完全相等,值相等,内存地址也相同。也就是说数组a和数组b实际上都是指向了同一个对象。上面修改了数组a的值,直接赋值得到的数组b的值也跟随变化。
2.浅拷贝
上面直接赋值的结果就是数组a和数组b完全相同,如果修改a,b也会跟着修改。实际上,我们可能不希望这样,我们希望复制过来的b和a进行区分,两者保持独立,不能互相影响。实现这个功能有一个方法就是Object的clone()方法。Object是Java的对象,所有类的父类。这个克隆实现的功能是:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
2.1 我们先看看如果字段是值类型,也就是八大基本数据类型的情况
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
int[] a = {40, 20, 50, 10, 60, 30};
int[] b = a.clone();
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,100);
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
运行结果:
false
a [40, 20, 100, 10, 60, 30]
b [40, 20, 50, 10, 60, 30] 上面可以看出,数组a是Int类型,也就是一个基本数据类型的数组,所以直接进行了值的复制。复制之后,数组b和数组a是内存地址不相等。如果我们操作数组a,数组b是不会受到影响。
2.2 看看如果是引用型的数组
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};
String[] b = a.clone();
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,"WuHan");
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
运行结果:
false
a [Beijing, ShangHai, WuHan, GuangZhou, XiAn]
b [Beijing, ShangHai, HeBei, GuangZhou, XiAn]
上面我们数组变成了String类型,里面的元素值也是String,我们知道String是一个类,不属于基本数据类型,所以,这里是引用类型。因为数组索引为2的元素是一个String类型,数组a和数组b的索引为2的元素都指向同一个索引,当修改a中引用指向的值是WuHan,数组b由于引用没有发生改变,所以值也没有跟着变化,还是指向了HeBei。clone()比较特殊,对于对象而言,它是深拷贝,但是对于数组而言,它是浅拷贝,因为数组每个元素如果是引用类型的话,数组本来存储的就是对象的引用。
2.3 System.arrayCopy()实现浅拷贝
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};
String[] b = new String[a.length];
System.arraycopy(a, 0, b, 0, a.length);
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,"WuHan");
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
2.4 Arrays.copyOf()实现浅拷贝
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};
String[] b = Arrays.copyOf(a, a.length);
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,"WuHan");
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
关于浅拷贝,推荐2.3或者2.4的方法,2.3执行速度更快。我分别测试了下,System.arraycopy显示0毫秒,而Arrays.copyOf()输出1毫秒。其实Arrays.copyOf()内部实现是调用了System.arraycopy方法。
3.深拷贝
深拷贝,就是说创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都进行复制。由于数组元素本来就存储对象的引用,所以,这里无法举例来实现数组的深拷贝。以后在类和对象的知识来介绍对象的深拷贝。
1.直接赋值
直接赋值很简单,例如Int a = 10, 第二行b=a,这里直接把a赋值给了b。这个时候,a和b是相等,内存地址相同,值也相等。我们用一个int基本类型的数组来举例。
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
int[] a = {40, 20, 50, 10, 60, 30};
int[] b = a;
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,100);
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
运行结果:
true
a [40, 20, 100, 10, 60, 30]
b [40, 20, 100, 10, 60, 30] 从运行结果看出:数组a和数组b确实是完全相等,值相等,内存地址也相同。也就是说数组a和数组b实际上都是指向了同一个对象。上面修改了数组a的值,直接赋值得到的数组b的值也跟随变化。
2.浅拷贝
上面直接赋值的结果就是数组a和数组b完全相同,如果修改a,b也会跟着修改。实际上,我们可能不希望这样,我们希望复制过来的b和a进行区分,两者保持独立,不能互相影响。实现这个功能有一个方法就是Object的clone()方法。Object是Java的对象,所有类的父类。这个克隆实现的功能是:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
2.1 我们先看看如果字段是值类型,也就是八大基本数据类型的情况
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
int[] a = {40, 20, 50, 10, 60, 30};
int[] b = a.clone();
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,100);
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
运行结果:
false
a [40, 20, 100, 10, 60, 30]
b [40, 20, 50, 10, 60, 30] 上面可以看出,数组a是Int类型,也就是一个基本数据类型的数组,所以直接进行了值的复制。复制之后,数组b和数组a是内存地址不相等。如果我们操作数组a,数组b是不会受到影响。
2.2 看看如果是引用型的数组
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};
String[] b = a.clone();
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,"WuHan");
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
运行结果:
false
a [Beijing, ShangHai, WuHan, GuangZhou, XiAn]
b [Beijing, ShangHai, HeBei, GuangZhou, XiAn]
上面我们数组变成了String类型,里面的元素值也是String,我们知道String是一个类,不属于基本数据类型,所以,这里是引用类型。因为数组索引为2的元素是一个String类型,数组a和数组b的索引为2的元素都指向同一个索引,当修改a中引用指向的值是WuHan,数组b由于引用没有发生改变,所以值也没有跟着变化,还是指向了HeBei。clone()比较特殊,对于对象而言,它是深拷贝,但是对于数组而言,它是浅拷贝,因为数组每个元素如果是引用类型的话,数组本来存储的就是对象的引用。
2.3 System.arrayCopy()实现浅拷贝
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};
String[] b = new String[a.length];
System.arraycopy(a, 0, b, 0, a.length);
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,"WuHan");
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
2.4 Arrays.copyOf()实现浅拷贝
package demo3;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* create by Anthony on 2017/10/29
*/
public class ArraysDemo {
public static void main(String args[]){
String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};
String[] b = Arrays.copyOf(a, a.length);
System.out.println(a == b);
//证明a发生变化,b会不会也变化
Array.set(a,2,"WuHan");
System.out.println("a "+Arrays.toString(a));
System.out.println("b "+Arrays.toString(b));
}
}
关于浅拷贝,推荐2.3或者2.4的方法,2.3执行速度更快。我分别测试了下,System.arraycopy显示0毫秒,而Arrays.copyOf()输出1毫秒。其实Arrays.copyOf()内部实现是调用了System.arraycopy方法。
3.深拷贝
深拷贝,就是说创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都进行复制。由于数组元素本来就存储对象的引用,所以,这里无法举例来实现数组的深拷贝。以后在类和对象的知识来介绍对象的深拷贝。
相关文章推荐
- 关于Java 拷贝数组方法 Arrays.copyOf() 是地址传递还是值传递
- Java数组拷贝方法arraycopy()
- java 数组 、 for each循环, 数组的两种拷贝方法 ,Arrays.copyOf(),Arrays.toString[],匿名数组
- java数组的拷贝四种方法:for、clone、System.arraycopy、arrays.copyof
- java 核心内容()数组拷贝的两种方法
- JavaScript和Java数组拷贝各种方法耗时比较
- 【Java基础】System的arraycopy方法拷贝数组
- Java基础知识强化85:System类之arraycopy()方法(数组拷贝)
- java基础之数组的拷贝(自定义方法与System下的自带方法对比)
- java数组的四种拷贝方法的性能分析:for、clone、System.arraycopy、Arrays.copyof
- Java学习之数组1(1.数组的声明;2.元素为引用数据类型的数组;3.关于main方法里的String[] args;4.数组排序;5.数3退1 数组算法,(用数组模拟链表);6数组查找之二分法;7数组的拷贝)
- java数组拷贝native方法
- java数组的拷贝四种方法:for、clone、System.arraycopy、arrays.copyof
- java数组拷贝的方法
- java语言基础——System类的数组拷贝方法
- 【Java】 数组拷贝的通用方法
- Java数组拷贝的四种方法
- Java中三种变量的拷贝方法比较: 值变量,对象变量,字符串变量
- Java遍历集合、数组的四种方法
- java byte型数组和16进制字符串互相转化方法