目录
一、 值传递和引用传递
二、引用传递的作用
三、浅拷贝与深拷贝
四、数组深拷贝
五、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>深拷贝
方式一:jdk8及以后可以使用流:
List<String> oneList = new ArrayList<String>();
oneList.add("1");
oneList.add("2");
oneList.add("3");
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]
六、List<Object>深拷贝
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>深拷贝
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<String, List<Map<String, Object>>>深拷贝
将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}]}
}
}
九、使用fastjson序列化深拷贝
上面的上面的例子都是通过实现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());
十、使用SerializationUtils深拷贝
除了上面的使用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}]}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80289.html