对象的 copy 你兴许只是懵懂, 或者是并没在意, 来了解下吧.
对于的 github 基础代码 https://github.com/chywx/JavaSE
最近学习 c++, 跟 java 很是相像, 在慕课网学习 c++ 也算是重温习了下 java 基础
明白了当初讲师一直强调 java 传递的话只有值传递, 不存在引用传递, 为什么一直要重复这, 既然只有值传递, 为啥还强调不是引用传递
毛病啊这是
学了 c++ 才知道, 原来 c++ 有值传递, 引用传递的说法, 但是 java 只是值传递
最简单的理解就是对于方法调用
比如 f(int a,int b) 这是值传递, 传递过来的值不会被修改.
再如 f(int &a,int &b)这是引用传递, 传递过来的值会被修改
步入正轨, 说一说 java 的浅拷贝(Shallow Copy), 深拷贝(Deep Copy).
浅拷贝 (Shallow Copy):对于数据类型是基本数据类型的成员变量, 浅拷贝会直接进行值传递, 也就是将该属性值复制一份给新的对象. 因为是两份不同的数据, 所以对其中一个对象的该成员变量值进行修改, 不会影响另一个对象拷贝得到的数据.对于数据类型是引用数据类型的成员变量, 比如说成员变量是某个数组, 某个类的对象等, 那么浅拷贝会进行引用传递, 也就是只是将该成员变量的引用值(内存地址) 复制一份给新的对象. 因为实际上两个对象的该成员变量都指向同一个实例. 在这种情况下, 在一个对象中修改该成员变量会影响到另一个对象的该成员变量值.
通过示例来了解下,
一:
使用构造函数实现 copy
- public class Person {
- public static void main(String[] args) {
- Son s = new Son(10);
- Person p1 = new Person("大海", s);
- Person p2 = new Person(p1);
- p1.setSonName("小海");
- p1.getSon().setAge(12);
- System.out.println("p1:" + p1);// p1:Person [sonName = 小海, son=Son [age=10]]
- System.out.println("p2:" + p2);// p2:Person [sonName = 大海, son=Son [age=10]]
- }
- private String sonName;
- private Son son;
- // 自定义拷贝函数
- public Person(Person person) {
- this.sonName = person.sonName;
- this.son = person.son;
- }
- public Person(String sonName, Son son) {
- super();
- this.sonName = sonName;
- this.son = son;
- }
- public String getSonName() {
- return sonName;
- }
- public void setSonName(String sonName) {
- this.sonName = sonName;
- }
- public Son getSon() {
- return son;
- }
- public void setSon(Son son) {
- this.son = son;
- }
- @Override
- public String toString() {
- return "Person [sonName=" + sonName + ", son=" + son + "]";
- }
- }
- class Son {
- private int age;
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public Son(int age) {
- super();
- this.age = age;
- }
- @Override
- public String toString() {
- return "Son [age=" + age + "]";
- }
- }
结果
p1:Person [sonName = 小海, son=Son [age=12]]p2:Person [sonName = 大海, son=Son [age=12]]
对于上面的实例, 该 person 对象有两个成员, 一个基本类型, 一个引用类型, 结果是拷贝出来的对象, 基本类型的那个成员真正的实现了 copy.
二:
使用自带的 clone 方法, 需要实现 cloneable 接口, 不然会
- Exception in thread "main" java.lang.CloneNotSupportedException:
- public class Person2 implements Cloneable {
- public static void main(String[] args) throws CloneNotSupportedException {
- Son2 son1 = new Son2(10);
- Person2 person1 = new Person2("大海", son1);
- Person2 person2 = (Person2) person1.clone();
- person2.setSon2Name("小海");
- person2.getSon2().setAge(12);
- System.out.println(person1);
- System.out.println(person2);
- }
- public Person2(String son2Name, Son2 son2) {
- super();
- this.son2Name = son2Name;
- this.son2 = son2;
- }
- private String son2Name;
- private Son2 son2;
- public String getSon2Name() {
- return son2Name;
- }
- public void setSon2Name(String son2Name) {
- this.son2Name = son2Name;
- }
- public Son2 getSon2() {
- return son2;
- }
- public void setSon2(Son2 son2) {
- this.son2 = son2;
- }
- @Override
- protected Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
- @Override
- public String toString() {
- return "Person2 [son2Name=" + son2Name + ", son2=" + son2 + "]";
- }
- }
- class Son2 {
- private int age;
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "Son2 [age=" + age + "]";
- }
- public Son2(int age) {
- super();
- this.age = age;
- }
- }
结果:
Person2 [son2Name = 大海, son2=Son2 [age=12]]Person2 [son2Name = 小海, son2=Son2 [age=12]]
使用自带的 copy 实现浅拷贝
---------------------------------------------------------------------------------------------------
深拷贝
相对于浅拷贝而言, 对于引用类型的修改, 并不会影响到对应的 copy 对象的值. 每一层的每个对象都进行浅拷贝 = 深拷贝.
一:
还是使用 clone 方法, 只不过得手动重写一下.
上代码
- public class Person3 implements Cloneable {
- public static void main(String[] args) throws CloneNotSupportedException {
- Son3 son1 = new Son3(10);
- Person3 person1 = new Person3("大海", son1);
- Person3 person2 = (Person3) person1.clone();
- person2.setSon2Name("小海");
- person2.getSon3().setAge(12);// 修改对应的引用对象的值.
- System.out.println(person1);
- System.out.println(person2);
- }
- public Person3(String son2Name, Son3 son3) {
- super();
- this.son2Name = son2Name;
- this.son3 = son3;
- }
- private String son2Name;
- private Son3 son3;
- public String getSon2Name() {
- return son2Name;
- }
- public void setSon2Name(String son2Name) {
- this.son2Name = son2Name;
- }
- public Son3 getSon3() {
- return son3;
- }
- public void setSon3(Son3 son3) {
- this.son3 = son3;
- }
- @Override
- protected Object clone() throws CloneNotSupportedException {
- Person3 clone = (Person3) super.clone();
- clone.setSon3((Son3) clone.getSon3().clone());
- return clone;
- }
- @Override
- public String toString() {
- return "Person3 [son2Name=" + son2Name + ", son3=" + son3 + "]";
- }
- }
- class Son3 implements Cloneable {
- private int age;
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "Son2 [age=" + age + "]";
- }
- public Son3(int age) {
- super();
- this.age = age;
- }
- @Override
- protected Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
- }
结果:
Person3 [son2Name = 大海, son3=Son2 [age=10]]
Person3 [son2Name = 小海, son3=Son2 [age=12]]
方法二:
显然对于多个对象的话, 显然就很吃力. 可以使用另一种方式,
将对象序列化为字节序列后, 默认会将该对象的整个对象图进行序列化, 再通过反序列即可完美地实现深拷贝.
- public class Person4 implements Serializable {
- public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
- Son4 son = new Son4(10);
- Person4 person1 = new Person4("大海", son);
- // 通过序列化方法实现深拷贝
- ByteArrayOutputStream bos=new ByteArrayOutputStream();
- ObjectOutputStream oos=new ObjectOutputStream(bos);
- oos.writeObject(person1);
- oos.flush();
- ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
- Person4 person2=(Person4)ois.readObject();
- person1.setSon4Name("小海");
- person1.getSon4().setAge(12);
- System.out.println(person1.toString());
- System.out.println(person2.toString());
- }
- public Person4(String son4Name, Son4 son4) {
- super();
- this.son4Name = son4Name;
- this.son4 = son4;
- }
- private String son4Name;
- private Son4 son4;
- public String getSon4Name() {
- return son4Name;
- }
- public void setSon4Name(String son4Name) {
- this.son4Name = son4Name;
- }
- public Son4 getSon4() {
- return son4;
- }
- public void setSon4(Son4 son4) {
- this.son4 = son4;
- }
- @Override
- public String toString() {
- return "Person4 [son4Name=" + son4Name + ", son4=" + son4 + "]";
- }
- }
- class Son4 implements Serializable {
- private int age;
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "Son2 [age=" + age + "]";
- }
- public Son4(int age) {
- super();
- this.age = age;
- }
- }
这是实现序列化接口方案, nice.
perfect!!! 到位
来源: https://www.cnblogs.com/c-h-y/p/9574586.html