Java 深拷贝 浅拷贝 +代码实现

您所在的位置:网站首页 java对象浅拷贝 Java 深拷贝 浅拷贝 +代码实现

Java 深拷贝 浅拷贝 +代码实现

2024-07-11 19:11| 来源: 网络整理| 查看: 265

今日目标 深拷贝 浅拷贝 一、前言

任何变成语言中,其实都有浅拷贝和深拷贝的概念,Java 中也不例外。在对一个现有的对象进行拷贝操作的时候,是有浅拷贝和深拷贝之分的,他们在实际使用中,区别很大,如果对其进行混淆,可能会引发一些难以排查的问题。

本文就在 Java 中的深拷贝和浅拷贝做一个详细的解说。这也是在面试时面试官可能会让写的。 特点:Java没有引用传递,Java只有值传递。

不想了解的话最后面有一点总结:!!

浅拷贝 基本数据类型直接copy值引用类型copy地址

首先implements Cloneable 这个接口 然后重写 clone() 方法

--------先写一个User实体类,实现Cloneable接口 并 并重写 clone()方法--------

public class User implements Cloneable{//Cloneable:JVM的标记接口,//并要重写克隆方法。 private int id; private String name; public User(){ super(); } public User(int id,String name){ super(); this.name=name; this.id=id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } //需要重写克隆方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }

------写完后测试一下---------

class test{ public static void main(String[] args) throws CloneNotSupportedException { User u1 = new User(1,"张三"); System.out.println(u1); System.out.println("--------拷贝的u1---------"); User u2 = (User) u1.clone(); System.out.println(u2); System.out.println("-------他们是否一样呢-----------"); System.out.println(u1==u2); System.out.println("-------此时我更改U1的值-----------"); u1.setName("李四"); System.out.println("u1:"+u1); System.out.println("u2:"+u2); System.out.println(u1==u2); } }

------效果------- 可以看出此时 拷贝还没有问题 是两个对象 改变里面一个类型的值 拷贝的不会影响 因为是两个对象 user实体里面存放的都是 基本数据类型 在这里插入图片描述 —————现在我们来加一个引用类型来看看—————— Address 实体类 存放一些地址信息

class Address { private String province; private String city; private String area; public Address() { super(); } public Address(String province, String city, String area) { super(); this.province = province; this.city = city; this.area = area; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getArea() { return area; } public void setArea(String area) { this.area = area; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Address address = (Address) o; return Objects.equals(province, address.province) && Objects.equals(city, address.city) && Objects.equals(area, address.area); } @Override public int hashCode() { return Objects.hash(province, city, area); } @Override public String toString() { return "Address{" + "province='" + province + '\'' + ", city='" + city + '\'' + ", area='" + area + '\'' + '}'; } }

————在User对象里加入这个引用类型————

在这里插入图片描述 User 引入后

public class User implements Cloneable{//Cloneable:JVM的标记接口,//并要重写克隆方法。 private int id; private String name; private Address address; public User(){ super(); } public User(int id,String name){ super(); this.name=name; this.id=id; } public int getId() { return id; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", address=" + address + '}'; } //需要重写克隆方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }

————测试一下————

class test2{ public static void main(String[] args) throws CloneNotSupportedException { User u1 = new User(1,"张三"); u1.setAddress( new Address ("河北省","保定市","莲池区")); System.out.println(u1); System.out.println("--------拷贝的u1---------"); User u2 = (User) u1.clone(); u2.getAddress().setArea("王者大陆"); System.out.println(u2); System.out.println(u1); //此时更改后的值(更改的是引用的值Address) 父类也发生了改变 //所以这是浅拷贝 只拷贝一层; //浅拷贝 拷贝的是引用值过去 具体还是操作的是一个 } }

------来看看效果—— 在这里插入图片描述 我们发现,修改Address里面的值后 克隆对象和父类对象都变了 这说明 克隆对象和父类对象修改的 Address 都是指向的一个 印证了上面说的 只拷贝一层 而且引用类型只是copy了地址 看下图 就知道了 在这里插入图片描述 这就是所谓的浅拷贝。

接下来看看深拷贝怎么写

深拷贝

深拷贝则需要 我们把Address也要拷贝

首先Address实现Cloneable接口 并 并重写 clone()方法

class Address implements Cloneable{ private String province; private String city; private String area; public Address() { super(); } public Address(String province, String city, String area) { super(); this.province = province; this.city = city; this.area = area; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getArea() { return area; } public void setArea(String area) { this.area = area; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Address address = (Address) o; return Objects.equals(province, address.province) && Objects.equals(city, address.city) && Objects.equals(area, address.area); } @Override public int hashCode() { return Objects.hash(province, city, area); } @Override public String toString() { return "Address{" + "province='" + province + '\'' + ", city='" + city + '\'' + ", area='" + area + '\'' + '}'; } }

然后User实体类 的clone()方法要改写 也就是在User的克隆方法处要对 Address克隆 并封装进克隆对象里返回给调用方法 在这里插入图片描述

public class User implements Cloneable{//Cloneable:JVM的标记接口,//并要重写克隆方法。 private int id; private String name; private Address address; public User(){ super(); } public User(int id,String name){ super(); this.name=name; this.id=id; } public int getId() { return id; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", address=" + address + '}'; } //需要重写克隆方法 @Override protected Object clone() throws CloneNotSupportedException { //深拷贝 克隆User对象 User user=(User) super.clone(); Address address=(Address) user.address.clone(); user.setAddress(address); return user; } }

-——————测试——————

class test2{ public static void main(String[] args) throws CloneNotSupportedException { User u1 = new User(1,"张三"); u1.setAddress( new Address ("河北省","保定市","莲池区")); System.out.println(u1); System.out.println("--------拷贝的u1---------"); User u2 = (User) u1.clone(); u2.getAddress().setArea("王者大陆"); System.out.println(u2); System.out.println(u1); //此时更改后的值(更改的是引用的值Address) 父类也发生了改变 //所以这是浅拷贝 只拷贝一层; //浅拷贝 拷贝的是引用值过去 具体还是操作的额一个 } }

————效果————

在这里插入图片描述 ——————看见了没 我们的深拷贝 的两个对象是完全不同的两个对象———— 也就是类似下图 在这里插入图片描述

总结 浅拷贝 基本数据类型直接copy值引用类型copy地址

特点:

(1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个。 (2) 对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响。

深拷贝 将引用类型也拷贝 并和父类封装返回得到两个完全独立的对象

特点

(1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。 (2) 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。 (3) 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。 (4) 深拷贝相比于浅拷贝速度较慢并且花销较大。

举例子的话就是: 浅拷贝:考试场景 小花是个没有感情的机器,啥也不会,考试的时候 小花抄了小明的卷子,但是小明把题解告诉了小花,小花有了自己的思维 ##可能小花觉得小明做的不对,因为小花有自己的思维了。 所以小明 小花在更改上述传递的答案的值时,互相都不干扰

但是有一个题 小明超了小黑的 这个题小黑没给小明讲解,所以小明没就没给小花讲解 所以小黑的值改了 他们两个都跟着改。 深拷贝:此时场景 小黑当时给小明抄的时候把题解告诉了小明 , 小明因为暗恋小花多年也直接把题解告诉了小花,这样小花也有了小黑的思想,自己随便更改值了。 那问题来了 小花最后是选择了谁作男朋友呢?? 哈哈 !! 其实这个例子不是很好,就大致那么个意思,我就这点水平哈哈。

告辞了 您嘞!!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3