Object

news/2024/11/13 19:43:23/文章来源:https://www.cnblogs.com/Chengkai730/p/18544638

Object 类是 Java 中的顶级父类, 所有的类都直接或间接继承于 Object 类.

Object 类中的方法可以被所有子类访问.

Object 类没有成员变量, 所以只有无参构造方法.

Java 中, 子类的共性才会往父类中去抽取, 然而不可能有一个属性是所有类的共性, 所以在 Object 这个类中, 是没有成员变量的.

任意一个类的构造方法, 在第一行, 都有一个隐藏的 super();, 默认访问父类的无参构造, 那为什么是默认访问无参构造而不是有参构造呢? 因为在顶级父类 Object 类中, 只有无参构造.

图片名称

Object 类一共有 11 个成员方法. 其中有三个最常见:

图片名称

程序示例:

public class demo1 {public static void main(String[] args) {/*public string tostring() 返回对象的字符串表示形式public boolean equals(Object obj) 比较两个对象是否相等protected object clone(int a) 对象克隆*/// 1.tostring 返回对象的字符串表示形式Object obj = new Object();String str1 = obj.toString();System.out.println(str1);  // java.lang.Object@119d7047// @ 前面是包名加类名, @ 是一个固定格式, @ 后面部分表示地址值// 对于自定义的类的对象, 也是同样的规则:Student stu = new Student();String str2 = stu.toString();System.out.println(str2);  //  Object_demo.Student@4eec7777// 直接打印对象, 和调用 toString 方法的效果是一样的:System.out.println(str1);  // java.lang.Object@119d7047System.out.println(str2);  //  Object_demo.Student@4eec7777// 细节:// System: 类名// out: 静态变量// System.out: 获取打印的对象// println(): 方法// 参数: 表示打印的内容// 核心逻辑:// 当我们打印一个对象的时候, 底层会调用对象的 tostring 方法, 把对象变成字符串// 然后再打印在控制台上, 打印完毕换行处理// 思考: 默认情况下, 因为 0bject 类中的 tostring 方法返回的的是地址值// 所以, 默认情况下, 打印一个对象打印的就是地址值// 但是地址值对于我们是没什么意义的// 我想要看到对象内部的属性值, 我们该怎么办?// 处理方案: 重写父类 0bject 类中的 toString 方法// tostring 方法的结论:// 如果我们打印一个对象, 想要看到属性值的话, 那么就重写 tcostring 方法就可以了// 在重写的方法中, 把对象的属性值进行拼接}
}

程序示例:

public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

toString() 源码:

图片名称

getClass().getName() 用于获取包名加类名, Integer.toHexString(hashCode()) 用于获取对象的地址值, 然后进行了一些复杂的运算, 再转换为 16 进制, 再和前面的内容进行了拼接.

第二个方法: equals(), 程序示例:

public class demo2 {public static void main(String[] args) {/*  public static boolean equals(Object obj)  比较两个对象是否相等  */Student student1 = new Student();Student student2 = new Student();boolean res = student1.equals(student2);System.out.println(res);   // false// 这里是用 Student 类的对象调用了 equals 方法,// 然而 Student 类显然没有 equals 方法, 因此是调用了 Object 里面的 equals 方法.// Object 里面的 equals 方法是用 == 号比较两个对象的地址值是否相同.// 这两个 Student 类的对象, 都是 new 出来的, 地址肯定是不一样的. 因此用 equals 方法将返回 false.// 地址值的比较其实意义不大, 往往真正希望比较的是两个对象内部的属性值是否相同.// 现在父类 Object 的 equals 方法就已经不能满足要求了, 于是就需要在子类 Student 中重写 equals 方法.// 重写这个 equals 方法, 并不需要我们自己手动书写, 可以借助 IDEA 的快捷键.// 过程很简单, 一直 next 既可, 最终生成了 equals 方法和 hashCode 方法, 但是 hashCode 方法暂时用不上, 可以选择先删除.}
}

Object 类中的 equals() 方法:

图片名称

Object 里面的 equals() 方法是用 == 号比较两个对象的地址值是否相同.

重写 Object 类里面的 equals() 方法的过程:

图片名称

重写之后的 Student 类:

import java.util.Objects;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}// 重写之后的 equals 方法比较的就是对象内部的属性值了.@Overridepublic boolean equals(Object o) {if (this == o) return true;  // 先比较是否为同一个对象, 如果是, 就没必要比较内容了, 直接返回 trueif (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;  // 强制类型转换return age == student.age && Objects.equals(name, student.name);}
}

此时比较两个 Student 类的对象, 比较的就是属性值了:

public class demo2 {public static void main(String[] args) {/*  public static boolean equals(Object obj)  比较两个对象是否相等  */Student student1 = new Student();Student student2 = new Student();Student student3 = new Student("zhangsan", 23);Student student4 = new Student("zhangsan", 23);boolean res1 = student1.equals(student2);boolean res2 = student3.equals(student4);System.out.println(res1);   // trueSystem.out.println(res2);   // true}
}

程序示例:

public class demo3 {public static void main(String[] args) {String s = "abc";StringBuilder sb = new StringBuilder("abc");// 这个 equals 方法是 s 调用的, 所以应该看 String 里面的 equals 方法System.out.println(s.equals(sb));  // false// 字符串中的 equals 方法, 先判断参数是否为字符串// 如果是字符串, 再比较内部的属性// 但是如果参数不是字符串, 直接返回 alse// 这里传递过来的显然不是字符串, 是一个 StringBuilder 对象// 这个 equals 方法是 sb 调用的, 所以应该看 StringBuilder 里面的 equals 方法System.out.println(sb.equals(s));  // false// 在 StringBuilder 当中, 没有重写 equals 方法// 使用的是 Object 中的// 在 Object 当中默认是使用 == 号比较两个对象的地址值// 而这里的 s 和 sb 记录的地址值是不一样的, 所以结果返回 false}
}

String 类里面的 equals() 方法:

图片名称

StringBuilder 类没有重写 equals() 方法:

图片名称

进入父类 AbstractStringBuilder 中查看, 发现也没有重写 equals 方法, 则是使用了 Object 类的 equals() 方法:

图片名称

第 3 个方法: clone()

作用: 把 A 对象的属性值完全拷贝给 B 对象, 也叫对象拷贝, 对象复制.

图片名称

可以看见, clone() 方法的修饰符为 protected, 所以 clone 方法只能被本包中的类和其他包中的子类使用, Object 类是写在 java.lang 包的, 显然我们不能把代码写在 lang 包下, 所以如果想要使用 clone() 方法, 就只能自己重写这个方法.

程序示例:

JavaBean 类:

// Cloneable
// 如果一个接口里面没有抽象方法
// 表示当前的接口是一个标记性接口
// 现在 Cloneable 表示一旦实现了, 那么当前类的对象就可以被克降
// 如果没有实现, 当前类的对象就不能克隆import java.util.StringJoiner;public class User implements Cloneable {private int id;private String username;private String password;private String path;private int[] data;public User() {}public User(int id, String username, String password, String path, int[] data) {this.id = id;this.username = username;this.password = password;this.path = path;this.data = data;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public int[] getData() {return data;}public void setData(int[] data) {this.data = data;}public String toString() {return "角色编号为: " + id + ", 用户名为: " + username + "密码为: " + password + ", 游戏图片为:" + path + ", 进度:" + arrToString();}public String arrToString() {StringJoiner sj = new StringJoiner(", ", "[", "]");for (int i = 0; i < data.length; i++) {sj.add(data[i] + "");}return sj.toString();}@Overrideprotected Object clone() throws CloneNotSupportedException {// 调用父类中的 clone 方法// 相当于让 Java 帮我们克隆一个对象, 并把克隆之后的对象返回出去. return super.clone();}
}

测试类:

public class demo4 {public static void main(String[] args) throws CloneNotSupportedException {// protected object clone(int a) 对象克隆// 1.先创建一个对象int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};User u1 = new User(1, "zhangsan", "1234qwer", "girl11", data);// 2.克隆对象// 细节:// 方法在底层会帮我们创建一个对象,并把原对象中的数据拷贝过去. // 书写细节:// 1.重写 Object 中的 clone 方法// 2.让 javabean 类实现 Cloneable 接口// 3.创建原对象并调用 clone 就可以了User u2 = (User) u1.clone();System.out.println(u1);System.out.println(u2);}
}

Java 中, 克隆有两种方式.

第一种方式, 先创建一个新的对象, 再把原来的对象的属性值全部拷贝到新对象中, 对于基本数据类型, 拷贝的是值, 对于引用类型的变量, 拷贝的是地址值.

如果有变量是记录着数组的地址的, 于是拷贝之后, 两个变量指向了同一个数组.

这种方式叫做浅克隆或者浅拷贝.

图片名称

第二种克隆方式, 也是会先创建一个对象, 对于各个属性, 如果是基本数据类型, 还是会将值直接拷贝过来, 如果是引用数据类型, 就不会直接拷贝地址值了, 而是会重新将这些引用型变量的地址所指向的内容, 全部再创建一份出来, 比如将原有的数组再创建出来一份一模一样的, 新老数组有不同的地址值, 新对象里面的属性记录的就是新数组的地址值. 对于字符串, 只要不是 new 出来的, 都是统一放在串池中进行管理的, 是会被复用的.

这种方式叫做深克隆或者深拷贝.

图片名称

Object 中的 clone() 方法, 是浅克隆.

public class demo4 {public static void main(String[] args) throws CloneNotSupportedException {// protected object clone(int a) 对象克隆// 1.先创建一个对象int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};User u1 = new User(1, "zhangsan", "1234qwer", "girl11", data);User u2 = (User) u1.clone();// 验证一件事情: Object 中的克隆是浅克隆// 想要进行深克隆, 就需要重写 clone 方法并修改里面的方法体int[] arr = u1.getData();arr[0] = 100;System.out.println(u1);System.out.println(u2);}
}

重写改写 Javabean 类:

// Cloneable
// 如果一个接口里面没有抽象方法
// 表示当前的接口是一个标记性接口
// 现在 Cloneable 表示一旦实现了, 那么当前类的对象就可以被克降
// 如果没有实现, 当前类的对象就不能克隆import java.util.StringJoiner;public class User implements Cloneable {private int id;private String username;private String password;private String path;private int[] data;public User() {}public User(int id, String username, String password, String path, int[] data) {this.id = id;this.username = username;this.password = password;this.path = path;this.data = data;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public int[] getData() {return data;}public void setData(int[] data) {this.data = data;}public String toString() {return "角色编号为: " + id + ", 用户名为: " + username + "密码为: " + password + ", 游戏图片为:" + path + ", 进度:" + arrToString();}public String arrToString() {StringJoiner sj = new StringJoiner(", ", "[", "]");for (int i = 0; i < data.length; i++) {sj.add(data[i] + "");}return sj.toString();}@Overrideprotected Object clone() throws CloneNotSupportedException {// 调用父类中的 clone 方法// 相当于让 Java 帮我们克隆一个对象, 并把克隆之后的对象返回出去. // 先把被克隆对象中的数组获取出来int[] data = this.data;// 创建新的数组int[] newData = new int[data.length];// 拷贝数组中的数据for (int i = 0; i < data.length; i++) {newData[i] = data[i];}// 调用父类中的方法克隆对象User u = (User) super.clone();// 因为父类中的克隆方法是浅克隆, 替换克隆出来对象中的数组地址值u.data = newData;return u;}
}
图片名称

借助第三方工具:

测试类:

public class demo4 {public static void main(String[] args) throws CloneNotSupportedException {// protected object clone(int a) 对象克隆// 1.先创建一个对象int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};User u1 = new User(1, "zhangsan", "1234qwer", "girl11", data);// 以后一般会用第三方工具进行克隆// 1. 第三方写的代码导入到项目中// 2. 编写代码Gson gson = new Gson();// 把对象变成一个字符串String s = gson.toJson(u1);// 再把字符串变回对象就可以了User user = gson.fromJson(s, User.class);int[] arr = u1.getData();arr[0] = 100;// 打印对象System.out.println(user);}
}

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

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

相关文章

Windows平台下安装与配置MySQL5.7

1.下载mysql安装文件 下载地址:https://downloads.mysql.com/archives/installer/2.安装与配置MySQL 双击打开,接受许可协议,点击下一步:选择自定义安装,点击下一步:选择要安装的产品,点击下一步:点击执行按钮:安装完成,点击下一步进入配置界面:配置界面继续点击下一…

C++ 逆向之常用字符集互转

在过往的编程过程中,常常会因为碰到字符集问题而头痛,而每次在进行字符集转换的时候,各种搜索网上文档,想找字符集转换的示例程序,但是都不尽人意,本篇文章的目的就是彻底解决之前编程过程中对字符集认识以及字符集转换之间似懂非懂、云里雾里的状态,并在文章结尾附上 A…

团队作业4——项目冲刺-1-第二篇

团队作业4——项目冲刺-1-第二篇这个作业属于哪个课程 <计科22级34班>这个作业要求在哪里 <作业要求>这个作业的目标 修改完善需求规格说明书、系统设计、Alpha任务分配计划、测试计划GitHub 链接 https://github.com/tangliweiwww/ChatGpt🍟一、团队 1.团队名称…

[Paper Reading] Fusing Monocular Images and Sparse IMU Signals for Real-time Human Motion Capture

目录名称TL;DRMethodLocal Pose EstimationRNN-P1RNN-P2RNN-P3Global Translation EstimationRNN-T1RNN-T2RNN-T3Hidden State Feedback MechanismExperiment效果可视化总结与发散相关链接 名称 link 时间:23.09 作者与单位:主页: https://github.com/shaohua-pan/RobustCap…

HarmonyOS Next 入门实战 - 创建项目、主题适配

​开发一个简单的demo,其中涉及一些鸿蒙应用开发的知识点,其中涉及导航框架,常用组件,列表懒加载,动画,深色模式适配,关系型数据库等内容,在实践中学习和熟悉鸿蒙应用开发。 ​​ ​​ 首先下载并安装DevEco Studio开发环境,下载完成后按照提示安装即可,过程不在多说…

rust学习八、包和模块

总体上,也没有什么特别的地方,和其它语言比较起来。 我们可以看懂熟悉的字眼:包括、模块、use、公共等等 如果是英文,则需要知道crate、pub。 本章节对应相关书籍的第七章节. 一、一个rust可执行程序的大体结构 就本章节而言,尚未接触到一个非常复杂的工程结构,据说有什么…

starrycan的pwn学习记录1

一.Introducation 0x01 简介CTF 0x02 什么是pwn ”Pwn”是一个黑客语法的俚语词,是指攻破设备或者系统 。发音类似“砰”,对黑客而言这就是成功实施黑客攻击的声音--砰的一声,被“黑”的电脑或手机就被你操纵了。 CTF中的pwn CTF中的PWN主要是针对于二进制漏洞挖掘与利用,通…

计算机组成原理与操作系统 第二章 处理机组成与管理

目录1.CPU的功能和组成1.1CPU的四大功能1.2CPU的基本组成1.3 一条指令如何在CPU内运行2.指令系统2.1机器语言与指令2.1.1基本概念2.1.2一条指令一般应包含的信息2.1.3指令的类型与功能2.1.4寻址方式2.2指令格式的设计2.2.1基本概念2.2.2指令类型2.2.3操作码类型2.2.4指令设计2.…

UWB无线通信技术

UWB定位与通信技术标准第2章 UWB无线通信技术 UWB(超宽带)技术最早诞生于无线通信领域,该新兴技术一出现就备受关注UWB信号有着极大的带宽,其时间分辨率高、抗多径效应能力强,被认为是高速率短距离无线通信中具有很强竞争力的候选方案之一为此,本章寻根溯源,从UWB无线通…

极速启动,函数计算弹性降本能力再升级

本文将深入探讨函数计算如何通过技术革新实现提效降本,以及其在 AI 业务、数据处理和 Web 应用等多个领域的广泛应用。作者:墨飏 在数字化转型的大潮中,云计算成为推动创新和优化业务流程的关键力量。作为阿里巴巴集团的核心产品之一,函数计算(Function Compute)引领着 S…

用函数实现模块化程序设计四

数组作为函数参数数组作为函数参数 调用有参函数时,需要提供实参,实参可以是常量、变量或表达式 数组元素的作用与变量相当,一般来说,凡是变量可以出现的地方,都可以用数组元素代替,因此,数组元素也可以用作函数实参,其用法与变量相同,向形参船体数组元素的值。此外,…