浅拷贝深拷贝

news2024/11/18 19:34:16

📋目录

  • 📚引入
  • 📚浅拷贝
    • 📖定义
    • 📖实现方式
    • 📖特点
  • 📚深拷贝
    • 📖 定义
    • 📖实现方式
    • 📖特点
  • 📚拓展
    • 📖Object类
      • ✈️toString()方法
      • ✈️equals()方法
      • ✈️hashcode方法
    • 📖通过方法实现实参的交换

在这里插入图片描述
在这里插入图片描述

📚引入

public class Person implements Cloneable{
    public int age;
    public String  name;

    public Person(String name,int age) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Test1 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person("zhangsan",10);
        Person person2=(Person)person1.clone();
    }
}

以上代码完善步骤
在这里插入图片描述
运行过程分析
在这里插入图片描述

📚浅拷贝

📖定义

创建一个新对象,新对象与原对象共享内部的引用对象,但基本数据类型的值是独立的

📖实现方式

示例代码如下

public class Money {
    public double money=9.9;
}

public class Person implements Cloneable{
    public int age;
    public String  name;
    public Money m=new Money();
    public Person(String name,int age) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Test1 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person("zhangsan",10);
        Person person2=(Person)person1.clone();
        System.out.println("修改前:"+person1.m.money);
        System.out.println("修改前:"+person2.m.money);
        person2.m.money=99.9;
        System.out.println("修改后:"+person1.m.money);
        System.out.println("修改后:"+person2.m.money);
    }
}
//执行结果
修改前:9.9
修改前:9.9
修改后:99.9
修改后:99.9

运行过程分析
在这里插入图片描述

📖特点

  • 效率相对较高,因为只复制了基本数据类型和引用地址,而不是复制整个引用对象。
  • 如果原对象中的引用对象发生变化,浅拷贝得到的新对象中的相应引用对象也会随之改变

📚深拷贝

📖 定义

创建一个新对象,新对象完全独立于原对象,包括内部的所有引用对象也都是独立复制的

📖实现方式

示例代码如下

若要在以上浅拷贝代码的基础上实现深拷贝则需要以下两步:

1.Money类实现Cloneable接口中的clone()方法

2.Student类中clone()方法中的return super.clone()条件改为
    Person tmp=(Person)super.clone();
    tmp.m=(Money)this.m.clone();
    return tmp;
public class Money implements Cloneable{
    public double money=9.9;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Person implements Cloneable{
    public int age;
    public String  name;
    public Money m=new Money();
    public Person(String name,int age) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp=(Person)super.clone();
        tmp.m=(Money)this.m.clone();
        return tmp;
    }
}

public class Test1 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person("zhangsan",10);
        Person person2=(Person)person1.clone();
        System.out.println("修改前:"+person1.m.money);
        System.out.println("修改前:"+person2.m.money);
        person2.m.money=99.9;
        System.out.println("修改后:"+person1.m.money);
        System.out.println("修改后:"+person2.m.money);
    }
}
//运行结果
修改前:9.9
修改前:9.9
修改后:9.9
修改后:99.9

运行过程分析
在这里插入图片描述

📖特点

  • 可以确保新对象与原对象完全独立,不会因为原对象的变化而受到影响。
  • 实现相对复杂,效率可能比浅拷贝低

📚拓展

📖Object类

Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父 类。即所有类的对象都可以使用Object的引用进行接收

范例:使用Object接收所有类的对象

class Person{}
class Student{}
public class Test {
    public static void main(String[] args) {
        function(new Person());
        function(new Student());
    }
    public static void function(Object obj) {
        System.out.println(obj);
    }
}
//执行结果:
Person@1b6d3586
Student@4554617c

Object类是参数的最高统一类型。但是Object类也存在有定义好的一些方法。如下:
在这里插入图片描述

✈️toString()方法

如果要打印对象中的内容,可以直接重写Object类中的toString()方法

// Object类中的toString()方法实现:
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
    //getClass():获取一个类的字节码对象
    //getClass().getName():获取一个类的全限定名(包名+类名)
    //hashCode():用于计算一个具体的对象位置(内存地址)
    //然后调用Integer.toHexString()方法,将这个地址以16进制输出
}

✈️equals()方法

在Java中,==进行比较时:

a.如果==左右两侧是基本类型变量,比较的是变量中值是否相同

b.如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同

c.如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的:

// Object类中的equals方法
public boolean equals(Object obj) {
    return (this == obj);   // 使用引用中的地址直接来进行比较
}
class Person{
 private String name ; 
 private int age ; 
 public Person(String name, int age) {
        this.age = age ; 
        this.name = name ;
 }
public class Test {
 public static void main(String[] args) {
 Person p1 = new Person("lisi", 20) ; 
 Person p2 = new Person("lisi", 20) ; 
        int a = 10;
        int b = 10;
        System.out.println(a == b);             // 输出true
        System.out.println(p1 == p2);           // 输出false
        System.out.println(p1.equals(p2));      // 输出false
 }
}

Person类重写equals方法后,然后比较:

class Person{
    ...
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false ;
        }
        if(this == obj) {
            return true ;
        }
        // 不是Person类对象
        if (!(obj instanceof Person)) {
            return false ;
        }
 
        Person person = (Person) obj ; // 向下转型,比较属性值
        return this.name.equals(person.name) && this.age==person.age ;
    }
}

结论:比较对象中内容是否相同的时候,一定要重写equals方法

✈️hashcode方法

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

源码中的hashCode()这个方法,用于计算一个具体的对象位置(内存地址),然后调用Integer.toHexString()方法,将这个地址以16进制输出

hashcode方法源码:

public native int hashCode();

该方法是一个native方法,底层是由C/C++代码写的,我们无法看到

一般认为两个名字相同,年龄相同的对象,将存储在同一个位置,在不重写hashcode()方法的情况下,观察以下示例代码的运行结果:

class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
   }
}
public class TestDemo4 {
    public static void main(String[] args) {
        Person per1 = new Person("lisi", 20) ;
        Person per2 = new Person("lisi", 20) ;
        System.out.println(per1.hashCode());
        System.out.println(per2.hashCode());
   }
}
//执行结果
460141958
1163157884

注意事项:两个对象的hash值不一样
像重写equals方法一样,我们也可以重写hashcode()方法,代码实现如下:

class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
   }
 
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
   }
}
public class TestDemo4 {
    public static void main(String[] args) {
        Person per1 = new Person("lisi", 20) ;
        Person per2 = new Person("lisi", 20) ;
        System.out.println(per1.hashCode());
        System.out.println(per2.hashCode());
   }
}
//执行结果
460141958
460141958

注意事项:哈希值一样
结论:

1、hashcode方法用来确定对象在内存中存储的位置是否相同
2、事实上hashCode()在散列表中才有用,在其它情况下没用。在散列表中hashCode()的作用是获取对象的散列码,进而确定该对象在散列表中的位置

📖通过方法实现实参的交换

public class Test1 {
    public static void swap(int x,int y){
        int tmp=x;
        x=y;
        y=tmp;
    }
    public static void main(String[] args) {
        int a=10;
        int b=20;
        System.out.println("交换前:"+a+" "+b);
        swap(a,b);//调用swap()函数只是交换了x和y的值,并未实现a和b的交换
        System.out.println("交换后:"+a+" "+b);
    }
}
//运行结果
交换前:10 20
交换后:10 20

交换过程

class MyValue{
    public int val;
}
public class Test1 {
    public static void swap(MyValue myV1,
                            MyValue myV2){
        int tem=myV1.val;
        myV1.val=myV2.val;
        myV2.val=tem;
    }
    public static void main(String[] args) {
        MyValue myValue1=new MyValue();
        MyValue myValue2=new MyValue();
        myValue1.val=10;
        myValue2.val=20;
        System.out.println("交换前:"+myValue1.val+" "+myValue2.val);
        swap(myValue1,myValue2);
        System.out.println("交换后:"+myValue1.val+" "+myValue2.val);
    }
}
//运行结果
交换前:10 20
交换后:20 10

交换过程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2172727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

预防工作场所的违规政策

违规政策是指未经管理层制定或批准的工作场所政策。 它们也可能直接违反公司政策。如果管理不善,这些政策可能会对您的业务产生负面影响。 最常见的流氓政策来源是 试图绕过现有政策框架的员工,或 经理们未经高层领导批准,擅自制定自己的…

《凡人歌》中的IT职业启示录

《凡人歌》是由中央电视台、正午阳光、爱奇艺出品,简川訸执导,纪静蓉编剧,侯鸿亮任制片,殷桃、王骁领衔主演,章若楠、秦俊杰、张哲华、陈昊宇主演的都市话题剧 ,改编自纪静蓉的小说《我不是废柴》。该剧于2…

基础漏洞——SSTI(服务器模板注入)

一.SSTI(服务器模板注入)的出现,框架漏洞 首先可以通过SSTI(Server-Side Template Injection)从名字可以看出即是服务器端模板注入。有些框架一般都采用MVC的模式。 用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对…

解决 Java 中由于 parallelStream 导致的死锁

并发性是软件开发的福音,也是祸根。通过并行处理提高性能的承诺与错综复杂的挑战相伴而生,例如臭名昭著的死锁。死锁是多线程编程世界中的隐患,它甚至可以使最强大的应用程序陷入瘫痪。它描述了两个或多个线程永远被阻塞,相互等待…

FOC矢量控制

目录 前言一、FOC简介1.1 FOC是什么1.2 FOC框图介绍 二、FOC坐标变换2.1 电流采集2.2 Clarke变换2.3 Park变换 三、闭环控制3.1 电流环控制3.3 速度环控制3.4 位置环控制 四、SVPWM原理4.1 空间矢量合成4.2 SVPWM法则4.3 MOS开关方式4.4 矢量作用时间 前言 本文主要介绍无刷直流…

未来医疗:从医技数字化2.0到全局变革

斯蒂芬•申弗(Stephen C. Schimpff)的《医疗大趋势:明日医学》被认为是全球第一本系统介绍未来医疗的权威著作。在书中,作者认为基因组学、手术技术革新、干细胞、数字医疗等关键技术将驱动医疗变革的发生,全面提升人类…

OpenAI o1-preview:详细分析

OpenAI 终于打破沉默,发布了万众期待的 “o1-preview”。其中有很多内容值得解读。 作为一家以 LLM 为生的人工智能初创公司,我们想知道这个新模型的性能如何,以及它能如何帮助我们改进产品。 因此,我花了一整天的时间来实验这个…

(JAVA)队列 和 符号表 两种数据结构的实现

1. 队列 1.1 队列的概述 队列是一种基于先进先出(FIFO)的数据结构,是一种只能在一端进行插入,在另一端进行删除操作的特殊线性表。 它按照先进先出的原则存储数据,先进入的数据,在读取时先被读出来 1.2 …

蓝桥杯【物联网】零基础到国奖之路:十二. TIM

蓝桥杯【物联网】零基础到国奖之路:十二. TIM 第一节 理论知识第二节 cubemx配置 第一节 理论知识 STM32L071xx器件包括4个通用定时器、1个低功耗定时器(LPTIM)、2个基本定时器、2个看门狗定时器和SysTick定时器。 通用定时器(TIM2、TIM3、…

详解JavaScript中属性getter和setter

6.6 属性getter和setter 属性值可以用1个或者2个方法替代,getter和setter. 由这两个定义的属性称作存取器属性(accessor property),不同于数据属性,只有一个简单的值。有读写属性,只能写,只能读,可以读写…

数据结构 算法的时间复杂度 计算(两种规则 加法原则+乘法原则)

在分析时间复杂性时,加法和乘法原则是两个基本且重要的概念,它们分别用于处理算法中顺序执行和嵌套执行的代码段的时间复杂度计算。以下是对这两个原则的详细说明: 一、加法原则 定义: 加法原则适用于顺序执行的代码段。如果一…

从Linux系统的角度看待文件-基础IO

目录 从Linux系统的角度看待文件 系统文件I/O open write read 文件操作的本质 vim中批量注释的方法 从Linux系统的角度看待文件 关于文件的共识: 1.空文件也要占用磁盘空间 2.文件内容属性 3.文件操作包括文件内容/文件属性/文件内容属性 4.文件路径文…

LDO实习报告(免费)-有完整电路版图

LDO实习任务书 实习目的: 了解LDO电路研究现状和原理结构,熟悉模拟电路设计流程。 week1 : 调研LDO应用情况及研究现状。 week2 : 熟悉LDO基本原理及组成。 week3 : 构建LDO电路。 week4 : 对LDO进…

从日志到洞察:轻松实现服务器安全管理的神器

在当今复杂多变的网络环境中,服务器安全管理已成为一项不可或缺的任务。然而,面对海量的日志数据,如何快速精准地提取有价值的信息,并及时发现潜在的安全威胁?本文将为您介绍一款强大的服务器日志检索与查杀工具&#…

pilz皮尔兹PSSuniversal分散控制平台 Dezentrale Steuerungsplattform 手测

pilz皮尔兹PSSuniversal分散控制平台 Dezentrale Steuerungsplattform 手测

WebAPI编程(第三天,第四天)

WebAPI编程(第三天,第四天) day03 - Web APIs1.1. 节点操作1.1.1 删除节点1.1.2 案例:删除留言1.1.3 复制(克隆)节点1.1.4 案例:动态生成表格1.1.5 创建元素的三种方式1.1.6 innerTHML和createE…

基于SSM+小程序的自习室选座与门禁管理系统(自习室1)(源码+sql脚本+视频导入教程+文档)

👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 1、管理员实现了首页、基础数据管理、论坛管理、公告信息管理、用户管理、座位管理等 2、用户实现了在论坛模块通过发帖与评论帖子的方式进行信息讨论,也能对账户进行在线充值…

深圳龙链科技:全球区块链开发先锋,领航Web3生态未来

【深圳龙链科技】是全球领先的Web3区块链技术开发公司,专注于为全球客户提供创新高效的区块链解决方案。 深圳龙链科技由币安资深股东携手香港领先的Web3创新枢纽Cyberport联袂打造,立足于香港这一国际金融中心,放眼全球,汇聚了华…

罕见,回复问询后闪电终止,业绩存下滑风险

《IPO魔女》认为,和美精艺利润低且大幅波动,报告期公司毛利率持续大幅下滑。而2023年同行业的上市公司均出现了业绩大幅下滑的情况,还未上市的和美精艺恐怕也存在业绩下滑的风险。此外,2020年至2022年,和美精艺研发投入…

Excel根据一个值匹配一行数据

根据一个值从一个表中匹配一行数据,例如从左边的表中找到指定姓名的所有行数据 使用VLOOKUP函数,参数: Lookup_value:需要搜索的值,单个值 Table_array:被搜索的区域,是个表 Col_index_num&…