
Java中的等号赋值
//基本数据类型通过等号赋值,肯定会生成一个新的地址,互不干扰int a = 10;int b = a; //把 a 赋值给 bb = 20;System.out.println("a : " + a);System.out.println("b : " + b);//对象数据类型User u = new User("zs", 10);User u1 = u;u.name = "ls";u.age = 20;//u修改后,u1的值也被修改;//通过打印地址也可以看出等号赋值操作后,两者指向同一个堆内存地址System.out.println(u + " " + u1);System.out.println(u1.name);//当u1赋值为null后,u和u1打印的地址已经不相等了//因为在赋值的同时,Java底层应该是对引用变量(栈内存中)//做了一个拷贝,拷贝模型如下,两者指向同一个 new User//栈内存 堆内存// u ------// | new User// u1 ------//因此从栈中的内存可以看出u和u1已经是不一样的内容了,//当u1 = null,不会对u产生任何影响u1 = null;System.out.println(u + " " + u1);
Java中的Clone
public static void main(String[] args) {Men m = new Men("zs" , 12, new Son("ww" , 10));try {Men m1 = (Men)m.clone();//通过打印发现两者地址不一样了,修改值也互不干涉//栈内存 堆内存(对一个Men对象)// m ------ new Men// |// m1 ------ new MenSystem.out.println("m1 == m " + m1 + " " + m);m.name = "ls";System.out.println("m1.name == m.name " + m1.name + " " + m.name);//假设在new Men中含有另一个对象,//而另一个对象没有实现Cloneable接口,又会发生什么情况呢?//打印后,会发现拷贝个 son 的地址是一样的,//也就是说在这里的拷贝没有完成对值的拷贝//通过对m的son赋值为null,发现和使用等号赋值后引用变量的变化一致,//也就是说还是拷贝了一次引用变量//栈内存 堆内存(不同的Men对象) 堆内存(同一个Son对象)// m ------ new Men ----// m.son// | new Son// m1 ------ new Men ----// m1.sonMen m2 = (Men)m.clone();System.out.println("m2.son == m.son " + m2.son + " " + m.son);m.son = null;System.out.println("m2.son == m.son " + m2.son + " " + m.son);} catch (CloneNotSupportedException e) {e.printStackTrace();}}static class Men implements Cloneable{String name;int age;Son son;public Men(String name , int age , Son son){this.name = name;this.age = age;this.son = son;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}}static class Son{String name;int age;public Son(String name , int age){this.name = name;this.age = age;}}
如何实现深拷贝
//实现深拷贝方式一//所有对象都实现Cloneable接口,重写Object中的clone方法public void fullCopyTypeOne(){try {User u = new User("zs" , 10 , new IDCard("123" , "成都"));User u1 = (User) u.clone();u.idCard.address = "上海"; //对原数据进行修改System.out.println("执行深拷贝后,对原数据进行修改后,拷贝后的数据:"+u1.idCard.address); //不影响深拷贝后的数据} catch (CloneNotSupportedException e) {e.printStackTrace();}}//实现深拷贝方式二//仿照C++,实现拷贝构造函数public void fullCopyTypeTwo(){User u = new User("zs" , 10 , new IDCard("123" , "成都"));User u2 = new User(u);u.idCard.idCard = "456";System.out.println("执行深拷贝后,对原数据进行修改后,拷贝后的数据:"+u2.idCard.idCard); //不影响深拷贝后的数据}
参数传递中内存拷贝
值传递
针对值传递是指基本变量的传递,肯定是执行了一次拷贝,基本变量肯定是一次深拷贝,因为执行拷贝后就是两个不同的内容了。
引用传递
/*** 交换指定数组中指定下标的值* @param arr* @param index0* @param index1*/public void swap(int[] arr , int index0 , int index1){System.out.print("打印被传递过来的形参:");for(int i : arr){System.out.print(i+" ");}System.out.println();int temp = arr[index0];arr[index0] = arr[index1];arr[index1] = temp;System.out.print("打印对形参执行交换后:");for(int i : arr){System.out.print(i+" ");}System.out.println();}/*** 将引用变量置为null*/public void change(int[] arr){arr = null;}public static void main(String[] args) {ParamerTransmit pt = new ParamerTransmit();int[] arr = new int[]{1,2};pt.swap(arr , 0 , 1);System.out.print("打印调用swap后的数据:");for(int i : arr){System.out.print(i+" ");}System.out.println();/*** 执行了代码后,可以看到通过对传递的形参所指向的对象* 进行操作的同时,原数据发生了改变,表示形参所指向的对象* 与原引用变量所指向的对象相同*/System.out.println("调用change方法前arr地址: "+arr);/***在change中置为null,对原始arr无影响,表示执行了一次浅拷贝,*将原始变量的引用变量做了一次拷贝*/pt.change(arr);System.out.println("调用change方法后arr地址: "+arr);}
总结
浅拷贝指拷贝对象的引用变量,不对对象内存中的值进行拷贝;深拷贝就是生成一个与原始数据地址完全不一样的数据。
实战经验-合理应用深浅拷贝
文中所有代码均可以在线下载:
https://gitee.com/wsyjiamian/JavaDiary.git
文章转载自程序员的日记本,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




