赞
踩
一、 值传递和引用传递
二、引用传递的作用
三、浅拷贝与深拷贝
四、数组深拷贝
五、List<String>深拷贝
六、List<Object>深拷贝
七、Map<String, String>深拷贝
八、Map<String, List<Map<String, Object>>>深拷贝
九、使用fastjson序列化深拷贝
十、使用SerializationUtils深拷贝
值传递:
以int类型为例,我们将a传入到方法changNumber中,在changNumber中将a修改为2。我们发现修改前后a都是一样的。
public class Maintest {
public static void main(String[] args) {
int a = 1;
System.out.println(a);//修改前输出 1
changNumber(a);
System.out.println(a);//修改后输出 1
}
public static void changNumber(int a) {
a = 2;
}
}
引用传递:
以MyInfo对象为例,我们将age设置为10传入到方法changAge中,在changAge中将age设置为20。我们发现修改前后age不一样了。
public class MyInfo {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Maintest {
public static void main(String[] args) {
MyInfo myinfo = new MyInfo();
myinfo.setAge(18);
System.out.println(myinfo.getAge()); //修改前输出 18
changAge(myinfo);
System.out.println(myinfo.getAge()); //修改后输出 20
}
public static void changAge(MyInfo myinfo) {
myinfo.setAge(20);
}
}
总结:
值传递:是将变量的值复制了一份进行传递,当复制的变量值改变了不会影响原本的变量值。比如:int、double、String、Integer、Double等基本类型以及包装类都是值传递。
引用传递:引用传递一般是对于对象型变量而言的,传递的是内存中对象的地址,所以传递后的内容改变了原本的内容也会改变。比如:List、Map、对象等都是引用传递。
举个形象的例子,有一个苹果有一条线吊着。值传递就是复制了另一个被线吊着的苹果,两者是无关的一个吃了一个不会影响另一个;引用传递就是从苹果上再牵一条线,无论你拉哪一条线吃苹果,苹果就一个吃了都会影响原来的。
对于基本类型传递的是值,对于引用类型传递的是对象的内存地址的值,所以有时候你会看到有的教程说Java里只有一种方式就是值传递,这里要理解它的意思。
changList可以不返回值就修改list,比如可以在changList中写对list的新增、删除、排序等,main方法中的list也会跟着被修改。
public class Maintest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
System.out.println(list);// 输出 [1]
changList(list);
System.out.println(list);// 输出 [1, 2]
}
public static void changList(List<Integer> list) {
list.add(2);
}
}
那万一我们想复制一份list数据传递到changList方法中,changList的list改变了而又不想改变main方法中的list呢,这就是我们下面要说的浅拷贝和深拷贝。
浅拷贝和深拷贝又被叫做浅复制和深复制,浅拷贝与深拷贝都是针对对象来说的。
浅拷贝:复制了一个对象,改变其中一个另外一个也会跟着改变,也就是上面说的引用传递。
深拷贝:复制了一个对象,两者完全隔离,也就是说改变其中一个另一个不受影响。
比如,我有一个List<String>类型的 listA,我想把 listA 复制一份得到 listB ,对 listA 进行增加删除数据不会影响 listB,同样对 listB 操作也不会影响 listA,这就是深拷贝。
浅拷贝就像上面引用传递示例那样,本文后面主要讲的都是深拷贝。
使用System.arraycopy拷贝基本数据类型的数组后,改变原始数组后,拷贝后的数组不会改变
int[] a1 = {1, 2, 3, 4, 5};
int[] a2 = new int[a1.length];
System.arraycopy(a1, 0, a2, 0, a1.length);//System.arraycopy参数说明:(原数组, 原数组的开始位置, 目标数组, 目标数组的开始位置, 拷贝个数)
System.out.println(Arrays.toString(a1)); // [1, 2, 3, 4, 5]
System.out.println(Arrays.toString(a2)); // [1, 2, 3, 4, 5]
下面的方式支持 List<String> 、List<Integer> 、List<Double> 类型深拷贝
方式一:通过初始化 new 来复制:
List<String> oneList = new ArrayList<String>();
oneList.add("1");
oneList.add("2");
oneList.add("3");
List<String> twoList = new ArrayList<>(oneList);
//也可以像下面注释的代码使用流来拷贝
//List<String> twoList = oneList.stream().collect(Collectors.toList());
System.out.println(oneList);//[1, 2, 3]
System.out.println(twoList);//[1, 2, 3]
方法二:使用addAll
List<String> oneList = new ArrayList<String>();
oneList.add("1");
oneList.add("2");
oneList.add("3");
List<String> twoList = new ArrayList<String>();
twoList.addAll(oneList);
System.out.println(oneList);//[1, 2, 3]
System.out.println(twoList);//[1, 2, 3]
方法三:使用Collections.copy
List<String> oneList = new ArrayList<>();
oneList.add("1");
oneList.add("2");
oneList.add("3");
List<String> twoList = new ArrayList<>(Arrays.asList(new String[oneList.size()]));//twoList要初始化大小
Collections.copy(twoList, oneList);
System.out.println(oneList);//[1, 2, 3]
System.out.println(twoList);//[1, 2, 3]
1.简单List<Object>的拷贝(即类里只含有基本数据类型或包装类型,不含List、Map等,也不嵌套对象。):
示例:
Student类:
需重写Cloneable中的clone()方法
public class Student implements Cloneable { public Integer id; public String name; //省略get、set方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "id:"+id+",name:"+name; } @Override public String toString() { return "id:"+id+",name:"+name; } }
public class Maintest { public static void main(String[] args) { Student student = new Student(); student.setId(1); student.setName("张三"); Student student1 = new Student(); student1.setId(2); student1.setName("李四"); List<Student> studentsList = new ArrayList<>(); studentsList.add(student); studentsList.add(student1); List<Student> studentsList1 = new ArrayList<>(); for (Student s:studentsList){ //循环取出每一个Student拷贝给一个临时的tempStudent,再add到studentsList1里 Student tempStudent = null; try { tempStudent = (Student) s.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } studentsList1.add(tempStudent); } //测试,studentsList里张三的i的 studentsList.get(0).setId(99); System.out.println(studentsList); //输出:[id:99,name:张三, id:2,name:李四] System.out.println(studentsList1); //输出:[id:1,name:张三, id:2,name:李四] } }
以上代码可简化为:
public class Student implements Cloneable { public Integer id; public String name; //省略get、set方法 @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } @Override public String toString() { return "id:" + id + ",name:" + name; } }
public class Maintest { public static void main(String[] args) { Student student = new Student(); student.setId(1); student.setName("张三"); Student student1 = new Student(); student1.setId(2); student1.setName("李四"); List<Student> studentsList = new ArrayList<>(); studentsList.add(student); studentsList.add(student1); //克隆 List<Student> studentsList1 = studentsList.stream().map(v ->(Student) v.clone()).collect(Collectors.toList()); //测试,studentsList里张三的i的 studentsList.get(0).setId(99); System.out.println(studentsList); //[id:99,name:张三, id:2,name:李四] System.out.println(studentsList1); //[id:1,name:张三, id:2,name:李四] }
2.复杂List<Object>的拷贝(即类里含有List、Map或者嵌套其他对象。):
Address类:
public class Address implements Cloneable{ public String type; public String value; //省略get、set方法 @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "type:"+type+",value:"+value; } }
Student类:
import java.util.List; public class Student implements Cloneable { public Integer id; public String name; public List<Integer> score; public Address address; //省略get、set方法 @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "id:"+id+",name:"+name+",score:"+score+",address:"+address; } }
public class Maintest { public static void main(String[] args) { List<Integer> sco=new ArrayList<>(); sco.add(90); Address addre = new Address(); addre.setType("111"); addre.setValue("home"); List<Integer> sco1=new ArrayList<>(); sco1.add(80); Address addre1 = new Address(); addre1.setValue("home"); addre1.setType("222"); //student赋值 Student student = new Student(); student.setId(1); student.setName("张三"); student.setScore(sco); student.setAddress(addre); //student1赋值 Student student1 = new Student(); student1.setId(2); student1.setName("李四"); student1.setScore(sco1); student1.setAddress(addre1); List<Student> studentsList = new ArrayList<>(); studentsList.add(student); studentsList.add(student1); List<Student> studentsList1 = new ArrayList<>(); //循环取出每一个Student拷贝给一个临时的tempStudent for (Student s : studentsList) { try { //循环取出每一个Student拷贝给一个临时的tempStudent Student tempStudent = (Student) s.clone(); //拷贝score到tempStudent里 List<Integer> tempScore=tempStudent.getScore(); List<Integer> score1 = new ArrayList<>(); score1.addAll(tempScore); tempStudent.setScore(score1); //拷贝address到tempStudent里 Address tempAddress=tempStudent.getAddress(); Address address1 = (Address)tempAddress.clone(); tempStudent.setAddress(address1); //tempStudent加到studentsList1里 studentsList1.add(tempStudent); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } //测试 studentsList.get(0).getScore().set(0,10); studentsList.get(0).getAddress().setValue("office"); //输出:[id:1,name:张三,score:[10],address:type:111,value:office, id:2,name:李四,score:[80],address:type:222,value:home] System.out.println(studentsList); //输出[id:1,name:张三,score:[90],address:type:111,value:home, id:2,name:李四,score:[80],address:type:222,value:home] System.out.println(studentsList1); } }
Map<String, String> paramMap1 = new HashMap<>();
paramMap1.put("name", "Marydon");
Map<String, String> paramMap2 = new HashMap<>();
paramMap2.putAll(paramMap1);
System.out.println(paramMap1);//输出 {name=Marydon}
System.out.println(paramMap2);//输出 {name=Marydon}
将map深拷贝到map1
public class Maintest { public static void main(String[] args) { Map<String, Object> ins = new HashMap<>(); ins.put("a-a",1); ins.put("a-b",2); Map<String, Object> ins1 = new HashMap<>(); ins1.put("b-c",3); ins1.put("b-d",4); List<Map<String, Object>> list = new ArrayList<>(); list.add(ins); list.add(ins1); Map<String, Object> ins2 = new HashMap<>(); ins2.put("c-e",5); ins2.put("c-f",6); Map<String, Object> ins3 = new HashMap<>(); ins3.put("d-g",7); ins3.put("d-h",8); List<Map<String, Object>> list1 = new ArrayList<>(); list1.add(ins2); list1.add(ins3); Map<String, List<Map<String, Object>>> map = new HashMap<>(); map.put("1",list); map.put("2",list1); Map<String, List<Map<String, Object>>> map1 = new HashMap<>(); //遍历map获取list,再遍历list获取map,由内到外的拷贝 for (Map.Entry<String, List<Map<String, Object>>> m: map.entrySet()){ List<Map<String, Object>> value= m.getValue(); List<Map<String, Object>> value1 = new ArrayList<>(); for(Map<String, Object> temmap:value){ Map<String, Object> temmap1=new HashMap<>(); temmap1.putAll(temmap); value1.add(temmap1); } map1.put(m.getKey(),value1); } //测试:改变map1里key是1的列表第0个元素的a-a为999 map1.get("1").get(0).put("a-a",999); System.out.println(map);//{1=[{a-a=1, a-b=2}, {b-d=4, b-c=3}], 2=[{c-e=5, c-f=6}, {d-h=8, d-g=7}]} System.out.println(map1);//{1=[{a-a=999, a-b=2}, {b-d=4, b-c=3}], 2=[{c-f=6, c-e=5}, {d-h=8, d-g=7}]} } }
上面的上面的例子都是通过实现Cloneable类来实现拷贝,可以通过fastjson序列化来实现拷贝
示例1:
比如上面的【List<Object>深拷贝>】中的复杂list<Object>的拷贝使用fastjson实现拷贝更简单,而且使用fastjson拷贝,Student和Address类都不用实现Cloneable类也不需要重写clone方法:
import com.alibaba.fastjson.JSONObject; import java.util.ArrayList; import java.util.List; public class Maintest { public static void main(String[] args) { List<Integer> sco=new ArrayList<>(); sco.add(90); Address addre = new Address(); addre.setType("111"); addre.setValue("home"); List<Integer> sco1=new ArrayList<>(); sco1.add(80); Address addre1 = new Address(); addre1.setValue("home"); addre1.setType("222"); //student赋值 Student student = new Student(); student.setId(1); student.setName("张三"); student.setScore(sco); student.setAddress(addre); //student1赋值 Student student1 = new Student(); student1.setId(2); student1.setName("李四"); student1.setScore(sco1); student1.setAddress(addre1); List<Student> studentsList = new ArrayList<>(); studentsList.add(student); studentsList.add(student1); //开始序列化拷贝,将studentsList拷贝给studentsList1 String listStr = JSONObject.toJSONString(studentsList); List<Student> studentsList1 = JSONObject.parseArray(listStr,Student.class); //测试 studentsList.get(0).getScore().set(0,10); studentsList.get(0).getAddress().setValue("office"); //输出:[id:1,name:张三,score:[10],address:type:111,value:office, id:2,name:李四,score:[80],address:type:222,value:home] System.out.println(studentsList); //输出[id:1,name:张三,score:[90],address:type:111,value:home, id:2,name:李四,score:[80],address:type:222,value:home] System.out.println(studentsList1); } }
示例2:
比如上面的【Map<String, List<Map<String, Object>>>深拷贝】使用fastjson实现拷贝更简单:
public class Maintest { public static void main(String[] args) { Map<String, Object> ins = new HashMap<>(); ins.put("a-a",1); ins.put("a-b",2); Map<String, Object> ins1 = new HashMap<>(); ins1.put("b-c",3); ins1.put("b-d",4); List<Map<String, Object>> list = new ArrayList<>(); list.add(ins); list.add(ins1); Map<String, Object> ins2 = new HashMap<>(); ins2.put("c-e",5); ins2.put("c-f",6); Map<String, Object> ins3 = new HashMap<>(); ins3.put("d-g",7); ins3.put("d-h",8); List<Map<String, Object>> list1 = new ArrayList<>(); list1.add(ins2); list1.add(ins3); Map<String, List<Map<String, Object>>> map = new HashMap<>(); map.put("1",list); map.put("2",list1); String listStr = JSONObject.toJSONString(map); Map<String, List<Map<String, Object>>> map1 = (Map)JSON.parse(listStr); //测试:改变map1里key是1的列表第0个元素的a-a为999 map1.get("1").get(0).put("a-a",999); System.out.println(map);//{1=[{a-a=1, a-b=2}, {b-d=4, b-c=3}], 2=[{c-e=5, c-f=6}, {d-h=8, d-g=7}]} System.out.println(map1);//{"1":[{"a-a":999,"a-b":2},{"b-d":4,"b-c":3}],"2":[{"c-e":5,"c-f":6},{"d-h":8,"d-g":7}]} } }
注意:
如果Map的key和value是非字符串的数值类型时,深拷贝后的key类型会变为字符串,value会变为Integer类型。
比如下面的拷贝会有问题:
Map<Long, Long> map = new HashMap<>();
map.put(1L,2L);
map.put(3L,4L);
String string = JSONObject.toJSONString(map);
//深拷贝为map1
Map<Long, Long> map1 = (Map)JSON.parse(string);
List<Long> keysList = map1.entrySet().stream()
.map(Map.Entry::getKey)
.collect(Collectors.toList());
List<Long> valuesList = map1.entrySet().stream()
.map(Map.Entry::getValue)
.collect(Collectors.toList());
//输出将报错,应为类型转换错误
System.out.println("class " + keysList.get(0).getClass());
System.out.println("class " + valuesList.get(0).getClass());
拷贝后的map1的key实际类型是String,value实际类型是Integer
正确的拷贝应该如下:
使用TypeReference
Map<Long, Long> map = new HashMap<>();
map.put(1L,2L);
map.put(3L,4L);
String string = JSONObject.toJSONString(map);
Map<Long, Long> map1 = JSON.parseObject(string,new TypeReference<Map<Long,Long>>(){});
List<Long> keysList = map1.entrySet().stream()
.map(Map.Entry::getKey)
.collect(Collectors.toList());
List<Long> valuesList = map1.entrySet().stream()
.map(Map.Entry::getValue)
.collect(Collectors.toList());
System.out.println("class " + keysList.get(0).getClass());
System.out.println("class " + valuesList.get(0).getClass());
除了上面的使用fastjson序列化实现深拷贝,还可以使用Apache Commons Lang3的SerializationUtils序列化实现深拷贝。
maven如下:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
示例1:
比如上面的【List<Object>深拷贝>】中的复杂list<Object>的拷贝使用SerializationUtils实现拷贝更简单:
Student类和Address类都要实现Serializable。
Student类:
import java.io.Serializable; import java.util.List; public class Student implements Serializable { public Integer id; public String name; public List<Integer> score; public Address address; //省略get、set方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "id:"+id+",name:"+name+",score:"+score+",address:"+address; } }
Address类:
import java.io.Serializable;
public class Address implements Serializable {
public String type;
public String value;
//省略get、set方法
@Override
public String toString() {
return "type:"+type+",value:"+value;
}
}
测试:
import org.apache.commons.lang3.SerializationUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class Maintest { public static void main(String[] args) { List<Integer> sco=new ArrayList<>(); sco.add(90); Address addre = new Address(); addre.setType("111"); addre.setValue("home"); List<Integer> sco1=new ArrayList<>(); sco1.add(80); Address addre1 = new Address(); addre1.setValue("home"); addre1.setType("222"); //student赋值 Student student = new Student(); student.setId(1); student.setName("张三"); student.setScore(sco); student.setAddress(addre); //student1赋值 Student student1 = new Student(); student1.setId(2); student1.setName("李四"); student1.setScore(sco1); student1.setAddress(addre1); List<Student> studentsList = new ArrayList<>(); studentsList.add(student); studentsList.add(student1); //使用SerializationUtils拷贝 List<Student> studentsList1 = (List<Student>)SerializationUtils.clone((Serializable)studentsList); //测试 studentsList.get(0).getScore().set(0,10); studentsList.get(0).getAddress().setValue("office"); //输出:[id:1,name:张三,score:[10],address:type:111,value:office, id:2,name:李四,score:[80],address:type:222,value:home] System.out.println(studentsList); //输出[id:1,name:张三,score:[90],address:type:111,value:home, id:2,name:李四,score:[80],address:type:222,value:home] System.out.println(studentsList1); } }
示例二:
比如上面的【Map<String, List<Map<String, Object>>>深拷贝】使用SerializationUtils实现拷贝更简单:
import org.apache.commons.lang3.SerializationUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Maintest { public static void main(String[] args) { Map<String, Object> ins = new HashMap<>(); ins.put("a-a",1); ins.put("a-b",2); Map<String, Object> ins1 = new HashMap<>(); ins1.put("b-c",3); ins1.put("b-d",4); List<Map<String, Object>> list = new ArrayList<>(); list.add(ins); list.add(ins1); Map<String, Object> ins2 = new HashMap<>(); ins2.put("c-e",5); ins2.put("c-f",6); Map<String, Object> ins3 = new HashMap<>(); ins3.put("d-g",7); ins3.put("d-h",8); List<Map<String, Object>> list1 = new ArrayList<>(); list1.add(ins2); list1.add(ins3); Map<String, List<Map<String, Object>>> map = new HashMap<>(); map.put("1",list); map.put("2",list1); Map<String, List<Map<String, Object>>> map1 = (Map) SerializationUtils.clone((Serializable)map); //测试:改变map1里key是1的列表第0个元素的a-a为999 map1.get("1").get(0).put("a-a",999); System.out.println(map);//{1=[{a-a=1, a-b=2}, {b-d=4, b-c=3}], 2=[{c-e=5, c-f=6}, {d-h=8, d-g=7}]} System.out.println(map1);//{1=[{a-a=999, a-b=2}, {b-d=4, b-c=3}], 2=[{c-e=5, c-f=6}, {d-h=8, d-g=7}]} } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。