【JAVA |再谈接口、Object、内部类】Object类中子类重写,Cloneable 接口、比较器、内部类

✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨ 
🎈🎈作者主页: 🎈丠丠64-CSDN博客🎈


✨✨ 帅哥美女们,我们共同加油!一起进步!✨✨ 

目录

一、前言

二、Obiect类

1.获取对象信息的打印

2.比较类中对象的异同

-equals方法

-hashcode方法

三、接口实现实例

-Comparable接口

-排序一个数组成员元素

1.直接使用接口Comparable

2.构造新的比较器

四、对象的拷贝

1.Cloneable拷贝

-浅拷贝

-深拷贝


一、前言

上一篇我们介绍了抽象类以及接口的相关知识,这篇我们来接着探讨一下关于接口的实例,并且认识一下所有类的父类Object


二、Obiect类

Object时JAVA中默认提供的一个类,所有的类都是继承Oject,换句话来说Oject是所有类的父类,这样就可以说在有需要实现一些功能的时候,子类方法就可以用重写来实现

1.获取对象信息的打印

我们首先来看这样一段代码

public class Person {public int age;public String name;public Person(int age, String name) {this.age = age;this.name = name;}
}
public class Test {public static void main(String[] args){Person person = new Person(16,"张三");System.out.println(person);} 
}

我们目的想要实现传入变量名字以后,打印出对应的成员属性,传入println()中是否能实现呢?

事实却是输出了这样一个值,为什么呢?我们跳转println函数定义去看

我们发现实现的最终函数是这个toString()前半部分是全路径,后面部分是类似地址一样的东西(后面会说)


toString()是Object的子类,所以我们只需要重写toString(),就可以随意实现我们的功能,所以修改一下这个代码重写toString()

public class Person {public int age;public String name;public Person(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Person{" + "age=" + age + ", name='" + name + '\'' + '}';}
}

即可实现我们的功能


2.比较类中对象的异同

首先我们先来看一段代码

        Person person1 = new Person(16,"张三");System.out.println(person1);Person person2 = new Person(16,"张三");System.out.println(person2);System.out.println(person1 == person2);

对于两个不同的变量,但是里面的成员属性却相同,比较person1和person2,他两会相等吗?

运行结果来看,两者是不同的,我们屏蔽掉刚写的toString()来看一下结果

发现原来是他们类似于地址一样的东西不一样!两个对象比较的其实是类似于地址的地址!

两个对象以不同的位置进行分配


-equals方法

在JAVA在有一个方法也是用来比较两个对象是否相等,就是equals(),我们跳转到定义去看

System.out.println(person1.equals(person2));

我发现它的定义只是这样(其中的this指谁调用equals谁就是this),跟刚才的person1 == person2没有区别,我们要实现我们的功能,对成员中的属性进行比较,因为equals是Object的子类,就要对其进行重写

@Overridepublic boolean equals(Object o) {if (this == o) {        return true;        //如果指向同一个对象为真}if (o == null || getClass() != o.getClass()) {return false;        //如果对象属性为空或者不是一个东西了为假}Person person = (Person) o;//向下转型比较属性值//判断对象中各个属性,都为真才为真return age == person.age && Objects.equals(name, person.name);}

通过调用自己重写的方法,这样这段代码就可以实现我们所需要的功能了,比较两个对象中各属性是否相等

        System.out.println(person1.equals(person2));

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

-hashcode方法

刚才在调用toString方法时我们看见了hashCode()这个方法,他帮我算了一个具体的对象位置,该方法是一个native方法,底层是由C/C++代码写的。我们看不到。

public native int hashCode();

我们来看一下这两个的值为多少 

System.out.println(person1.hashCode());
System.out.println(person2.hashCode());

因为两者所分配的空间不同,所以对象位置也不相同,返回的值也就不相同,倘若我们现在想要实现,为两个名字相同,年龄相同的对象,将存储在同一个位置,hashcode是Object的子类,我们就要重写hashcode()方法

 @Overridepublic int hashCode() {return Objects.hash(age, name);}

再输出我们结果,发现经过一系列算法,两个对象出现了同一位置

两个对象的hash值不一样,hashcode方法用来确定对象在内存中存储的位置是否相同

三、接口实现实例

我们先看这样一个代码

public class Student {public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}

当我们想实现两个变量之间的比较,是不是直接比较他们两个变量是否相等然后返回布尔值就行了呢?答案是错的,引用类型变量不可以这样比较,直接比较会报错

public class Test {public static void main(String[] args){Student student1 = new Student(12,"小明");Student student2 = new Student(15,"小美");System.out.println(student1 > student1);}}


-Comparable接口

自定义想要比较大小,就要实现这个接口

我们应该在Student这个类给它加上一个Comparable接口,再把Student传进去就可以进行比较了

public class Student implements Comparable<Student>{public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}

但是我们发现还是会报错,我们跳转过去定义查看

发现需要按照自己的需求去重写这个compareTo方法

假如说我们需要按照年龄去比较两个对象,于是就可以这样重写

@Overridepublic int compareTo(Student o) {return this.age - o.age;  //大于输出正数,小于输出负数,相等输出0}

这样就不会报错了

System.out.println(student1.compareTo(student2));
System.out.println(student2.compareTo(student1));

输出结果

-排序一个数组成员元素

1.直接使用接口Comparable

先实现一个学生的类,并且使用接口Comparable

public class Student implements Comparable<Student>{public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(Student o) {return this.age - o.age;  //大于输出正数,小于输出负数,相等输出0}
}

定义一个学生的数组

Student[] students = new Student[3];students[0] = new Student(18,"小明");
students[1] = new Student(15,"小礼");
students[2] = new Student(21,"小花");

然后根据冒泡排序对学生的年龄对其排序

public static void my_sort(Comparable[] comparable){for (int i = 0; i < comparable.length - 1; i++) {for (int j = 0; j < comparable.length - 1 - i; j++) {if (comparable[j].compareTo(comparable[j+1]) > 0){Comparable tmp = comparable[j];comparable[j] = comparable[j+1];comparable[j+1] = tmp;}}}}

打印出结果,对其学生年龄进行排序

my_sort(students);
System.out.println(Arrays.toString(students));

结果成立

但是这种方法也有很大的危害,对类的侵入性比较强,也不够灵活


2.构造新的比较器

所以基于上述的的危害我们可以进行优化

对于年龄比较,我们新建一个类AgeComparator,并对其compare进行重写即可

class AgeComparator implements Comparator<Student> {@Overridepublic int compare(Student o1,Student o2) {return o1.age - o2.age;  }
}

对于名字比较,我们新建一个类NameComparator,并对其compare进行重写即可

class NameComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}

我们来实现一下,分别以年龄跟名字比较

        Student student1 = new Student(12,"zahngsan");Student student2 = new Student(15,"lisi");NameComparator nameComparator = new NameComparator();System.out.println(nameComparator.compare(student1, student2));AgeComparator ageComparator = new AgeComparator();System.out.println(ageComparator.compare(student1, student2));

结果成立,且互不干扰,这就是比较器的好处,比较灵活,对类的侵入性不强


四、对象的拷贝

我们先构造一个类,并且实例化一个对象

public class Person {public int age;public Person(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}
}
public class Test {public static void main(String[] args){Person person1 = new Person(19);}
}

实例化的对象person1他在内存中是这样分配的,对象的属性在堆区开辟了空间地址由persin1保存

倘若我们要实现对变量person1进行一份拷贝,如何实现呢?


1.Cloneable拷贝

我们先介绍Cloneable接口,我们先跳转过定义,可以看到是一个空接口

又称为标记接口:证明当前类是可以被克隆的

我们实例化第二个对象,用JAVA中提供的clone 方法,创建一个对象的 "拷贝"

Person person2 = person1.clone();

但是我们发现报错了,我们还要经过以下三步

clone属于Obiect中的方法,我们转到clone的定义,发现他的访问权限是protected,直接访问不到只能够重写这个方法

但是同时呢我们发现还多了一个 throws CloneNotSupportedException这样的东西,必须是编译时处理,所以我们也要在main主函数上加上 throws CloneNotSupportedException

同时呢用我们发现它的返回值为Object,父类访问子类中的方法就是发生向下转型强转为Person类型

    @Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person(19);Person person2 = (Person) person1.clone();}
}

同时也要加接口,来证明这个类可以被克隆

public class Person implements Cloneable{public int age;public Person(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}protected Object clone() throws CloneNotSupportedException {return super.clone();}
}

不加接口则会报错

至此编译正常通过

public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person(19);Person person2 = (Person) person1.clone();System.out.println(person1);System.out.println(person2);}
}

成功克隆


-浅拷贝

我们来看以下的这段代码

构造了个Money、Perso两个类,重写了clone

class Money {public double m = 99.99;
}class Person implements Cloneable{public Money money = new Money();@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

person1拷贝一份persona2,并且修改persinal2的值,理想的结果应该是persinal2的m值被修改,person1的不变

public class Test{public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person();Person person2 = (Person) person1.clone();System.out.println("通过person2修改前的结果");System.out.println(person1.money.m);System.out.println(person2.money.m);person2.money.m = 13.6;System.out.println("通过person2修改后的结果");System.out.println(person1.money.m);System.out.println(person2.money.m);}

但是输出结果并不是这样,我们发现persona1中的m也被修改了,为什么会这样呢?

我们发现拷贝只拷贝了一份新的对象,并没有拷贝对象中的元素,对象中的元素位置没有被改变,两个对象中的m指向了同一块内存,同一个吗,对象中的元素没有被克隆,所以两者都可以修改,这种没有完全拷贝就称为浅拷贝


-深拷贝

  我们对以上的代码进行修改,将clone进行重写,将对象中的对象也进行拷贝,这个问题就解决了

@Overrideprotected Object clone() throws CloneNotSupportedException {Person tmp = (Person) super.clone();tmp.money = this.money.clone();}

深浅拷贝说白了就是重写clone方法实现的,方法内部实现的不一样


希望对你有帮助

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

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

相关文章

Internet动态路由选择—RIP与OSPF

刚做完网络层动态路由选择的实验&#xff0c;写下此篇记录实验过程&#xff0c;巩固学习成果。 参考书目&#xff1a;《计算机网络》北京理工大学出版社-刘阳老师编 路由选择可分为两种策略&#xff1a; - 静态路由选择策略 - 动态路由选择策略 静态路由即管理员手动配置路由…

Java 商品入库系统 案例

测试类 package 练习.商品入库系统;import java.util.ArrayList; import java.util.Scanner; public class Test {public static final int Enrool 1;public static final int Search 2;public static final int Delect 3;public static final int Exit 4;public static…

在docker上部署postgresSQL主从

文章目录 一、主从规划二、创建PostgresSQL的Docker镜像三、主库部署1、建立pgsql主库的data地址2、启动docker镜像3、docker内操作4、修改配置文件 四、部署从数据库1、建立psql备库的data地址2、启动docker镜像3、备库从主库同步4、检查是否同步 五、测试主从数据库 一、主从…

#2495. 滑动窗口 /【模板】单调队列

题目描述 有一个长为 ( n ) 的序列 ( a )&#xff0c;以及一个大小为 ( k ) 的窗口。现在这个窗口从左边开始向右滑动&#xff0c;每次滑动一个单位&#xff0c;求出每次滑动后窗口中的最大值和最小值。例如&#xff1a; 数组是 ([1, 3, -1, -3, 5, 3, 6, 7])&#xff0c; ( …

【深度强化学习】关于同一设备上cuda和gpu计算结果不一致问题

文章目录 问题描述关于seed: 跟原文一致补充:万能seed 问题结论cpu和gpu差异来源分析浮点数精度的差异补充报错&#xff1a;Expected all tensors to be on the same device&#xff01;常见运算上的差异累加运算的差异exp运算的差异matmul运算的差异 forward上的差异&#xff…

【LeetCode 随笔】面试经典 150 题【中等+困难】持续更新中。。。

文章目录 189. 轮转数组122. 买卖股票的最佳时机 II55. 跳跃游戏45. 跳跃游戏 II274. H 指数 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01; &#x1f49d;希望您在这里可以感受到一份轻松…

机器学习云环境搭建

在 https://support.huaweicloud.com/browsertg-obs/obs_03_1003.html 下载对应版本的 OBS Broswer 软件&#xff0c;如图&#xff0c;红框内的为安装文件&#xff0c;蓝色框内的为对应安装文件的校验文件&#xff08;无需下载&#xff09; 以 64 位机为例&#xff0c;下载完…

景源畅信电商:抖店需要的成本高吗?

在数字化时代的浪潮中&#xff0c;短视频平台迅速崛起&#xff0c;成为连接用户与商家的新桥梁。抖音作为其中的佼佼者&#xff0c;不仅改变了人们的娱乐方式&#xff0c;也催生了新型的电商模式——抖店。许多人好奇&#xff0c;入驻这样一个充满活力的平台&#xff0c;需要承…

618知识狂欢,挑本好书,点亮智慧生活!

618精选编程书单&#xff1a;提升你的代码力 一年一度的618又到啦&#xff01;今年的618就不要乱买啦&#xff0c;衣服买多了会被淘汰&#xff0c;电子产品买多了会过时&#xff0c;零食买多了会增肥&#xff0c;最后怎么看都不划算。可是如果你购买知识&#xff0c;坚持阅读&a…

第N2周:Embeddingbag与Embedding详解

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 目录 什么是词嵌入&#xff1f; Embedding与EmbeddingBag详解 Embedding Embeddi…

代码随想录算法训练营第十七天|LeetCode110 平衡二叉树、LeetCode257 二叉树的所有路径

题1&#xff1a; 指路&#xff1a;LeetCode110 平衡二叉树 思路与代码&#xff1a; 左右子树的高度差小于等于1。对于这个题&#xff0c;递归比迭代方便太多&#xff0c;我也想过迭代&#xff0c;但是我没有写出来&#xff0c;大家可以自己试一下。递归代码如下&#xff1a;…

如何为ChatGPT编写有效的提示词:软件开发者的指南

作为一名软件开发者&#xff0c;特别是使用Vue进行开发的开发者&#xff0c;与ChatGPT等AI助手高效互动&#xff0c;可以极大地提升你的开发效率。本文将深入探讨如何编写有效的提示词&#xff0c;以便从ChatGPT中获取有用的信息和帮助。 1. 明确目标 在编写提示词之前&#…

后端之路第二站(正片)——SprintBoot之:分层解耦

很抽象&#xff0c;我自己也不好理解&#xff0c;仅作为一个前端转后端的个人理解 一、先解释一个案例&#xff0c;以这个案例来分析“三层架构” 这里我先解释一下黑马程序员里的这个案例&#xff0c;兄弟们看视频的可以跳过这节课&#xff1a;Day05-08. 请求响应-响应-案例_…

【webrtc】m98:Call的创建及Call对音频接收处理

call中多個流共享相同的辅助组件 这几个是与外部共用的 线程传输send控制module 线程任务队列工厂call的辅助组件中各种统计以及接收测的cc是自己创建的 call自己的多个辅助组件是外部传递来的 call 创建多个接收流 这里用一个set 来保存所有指针,并没有要map的意思:

【因果推断从入门到精通二】随机实验3

目录 检验无因果效应假说 硬币投掷的特殊性何在&#xff1f; 检验无因果效应假说 无因果效应假说认为&#xff0c;有些人存活&#xff0c;有些人死亡&#xff0c;但接受mAb114治疗而不是ZMapp与此无关。在174例接受mAb14治疗的患者中&#xff0c;113/17464.9%存活了28天&…

【MySQL精通之路】InnoDB(6)-磁盘结构

主要博客&#xff1a; 【MySQL精通之路】InnoDB存储引擎-CSDN博客 1 表 2 索引 【MySQL精通之路】InnoDB(6)-磁盘结构(2)-索引-CSDN博客 3 表空间 【MySQL精通之路】InnoDB(6)-磁盘结构(3)-表空间-CSDN博客 4 双写缓冲区 【MySQL精通之路】InnoDB(6)-磁盘结构(4)-双写缓冲…

修改MySQL root用户密码

ALTER USER ‘root’‘localhost’ IDENTIFIED BY ‘new_password’; ALTER USER ‘root’‘%’ IDENTIFIED BY ‘new_password’; 》 SET GLOBAL read_only OFF; select * from mysql.user;

Java入门基础学习笔记47——ArrayList

什么是集合呢&#xff1f; 集合是一种容器&#xff0c;用来装数据的&#xff0c;类似数组。 有数组&#xff0c;为什么还要学习集合呢&#xff1f; 数组定义完成并启动后&#xff0c;长度就固定了。 而集合是大小可变&#xff0c;开发中用的最多的。 集合的特点&#xff1a;大…

汇聚荣科技有限公司优点有哪些?

在当今快速发展的科技时代&#xff0c;企业之间的竞争愈发激烈。作为一家专注于科技创新与研发的公司&#xff0c;汇聚荣科技有限公司凭借其卓越的技术实力和创新能力&#xff0c;在业界树立了良好的口碑。那么&#xff0c;汇聚荣科技有限公司究竟有哪些优点呢?接下来&#xf…