Java核心-你真的知道Object吗(Object:所有类的超类)

news2024/11/28 3:34:35

作者:逍遥Sean
简介:一个主修Java的Web网站\游戏服务器后端开发者
主页:https://blog.csdn.net/Ureliable
觉得博主文章不错的话,可以三连支持一下~ 如有需要我的支持,请私信或评论留言!

前言
今天来聊一聊对象😍(bushi👋)!!!
👇👇👇
众所周知,Java每个类都是对象,Object类是Java中所有类的始祖,在Java中每个类都扩展了Object。但是并不需要这样写:

public class Employee extends Object

如果没有明确的指出超类,Object就被认为是这个类的超类。由于在Java中每个类都是由Object扩展而来的。所以熟悉这个类提供的所有服务十分重要。文章将介绍一些基本的内容,没有提到的内容大多是涉及并发操作的,后续将有文章介绍哦~

Object:所有类的超类

  • 1 Object类型的变量
  • 2 equals方法
  • 3 相等测试与继承
  • 4 hashCode方法
  • 5 toString方法

1 Object类型的变量

可以使用Object类型的变量引用任何类型的对象

Object obj = new String("Hello");

Object可以用来声明一个指向任何对象的引用变量,以及作为方法的参数和返回类型。例如:

Object obj = new String("Hello");
obj = new Integer(10);
obj = new MyClass();

当然,Object只能是作为各种值的一个泛型容器。想要对其中的内容进行具体的操作,还是需要清楚对象的原始类型,并进行相应的强制转换:

Object obj = new MyClass();
MyClass mc = (MyClass) obj;

在这里,obj变量被声明为Object类型,因此可以先将它指向一个String对象,然后又改为指向一个Integer对象,最后又指向一个自定义的MyClass对象。注意,当obj变量指向不同类型的对象时,需要进行类型转换才能访问其特定的方法和属性。

在Java中,只有基本数据类型不是对象

所有的数组结构也继承了Object
例如:

MyClass[] mcs = new MyClass[];
Object obj = mcsl; //OK

2 equals方法

Java的equals方法是一个用于比较两个对象是否相等的方法。它是Object类中定义的方法,并且可以被任何类继承和重写。
在Java中,如果两个对象的内容相同,则它们被认为是相等的。因此在比较两个对象是否相等时,需要考虑对象的内容而不是对象的引用。
例如,假设我们有一个名为Employee 的类。我们可以通过如下的方式实现equals方法:

public class Employee {
    // 省略属性声明
	...
	public boolean equals(Object otherObject)
	{
		// a quick test to see if the objects are identical
		if (this == otherObject) return true;
		// must return false if the explicit parameter is null
		if (otherObject == null) return false;
		// if the classes don't match, they can't be equal
		if (getClass() != otherObject.getClass())
		return false;
		// now we know otherObject is a non-null Employee
		Employee other = (Employee) otherObject;
		// test whether the fields have identical values
		return name.equals(other. name)
		&& salary = other.salary
		&& hireDay. equals(other,hireDay):
    }
}

这个equals方法首先检查传递进来的对象是否为空或者是否指向当前对象,如果是则直接返回true或false。接下来,它检查传递进来的对象是否是Employee类的实例。如果不是,则返回false。最后,它将传递进来的对象转换成Employee对象,并比较它们的name和salary字段是否相等。如果这两个字段相等,则返回true,否则返回false。

注:上述代码中,为了防备name可能为null的情况,需要使用Object.equals方法,如果两个参数都是null,Object.equals会返回true;如果其中一个参数都是null,Object.equals会返回false;如果两个参数都不是null,Object.equals会调用a.equals(b)

在子类中定义 equals 方法时, 首先调用超类的 equals。如果检测失败, 对象就不可能相等。如果超类中的域都相等, 就需要比较子类中的实例域。

public class Manager extends Employee {
	public boolean equals(Object otherObject){
		if (!super.equals(otherObject)) return false;
		Manager other = (Manager) otherObject;
		return bonus == other.bonus;
	}
}

3 相等测试与继承

如果隐式和显式的参数不属于同一个类, equals 方法将如何处理呢? 这是一个很有争议的问题。 在前面的例子中, 如果发现类不匹配, equals 方法就返冋 false。但是, 许多程序员却喜欢使用 instanceof 进行检测:

if ( !(otherObject instanceof Employee)) return false;

这样做不但没有解决 otherObject 是子类的情况,并且还有可能会招致一些麻烦。这就是建议不要使用这种处理方式的原因所在。
Java 语言规范要求 equals 方法具有下面的特性:

  1. 自反性:对于任何非空引用 x, x.equals(x) 应该返回 true;
  2. 对称性: 对于任何引用 x 和 y, 当且仅当 y.equals(x) 返回 true , x.equals(y) 也应该返回 true;
  3. 传递性: 对于任何引用 x、 y 和 z, 如果 x.equals(y) 返回 true, y.equals(z) 返回 true,x.equals(z) 也应该返回 true;
  4. 一致性: 如果 x 和 y 引用的对象没有发生变化,反复调用 x.equals(y) 应该返回同样的结果;
  5. 非空性:对于任意非空引用 x, x.equals(null) 应该返回 false。

这些规则十分合乎情理,从而避免了类库实现者在数据结构中定位一个元素时还要考虑调用 x.equals(y), 还是调用 y.equals(x) 的问题。
然而, 就对称性来说, 当参数不属于同一个类的时候需要仔细地思考一下。请看下面这个调用:

e.equals(m)

这里的 e 是一个 Employee 对象, m 是一个 Manager 对象, 并且两个对象具有相同的姓名、薪水和雇佣日期。 如果在 Employee.equals 中用 instanceof 进行检测, 则返回 true. 然而这意味着反过来调用:

m.equals(e)

也需要返回 true。但对称性不允许这个方法调用返回 false,或者抛出异常。
这就使得 Manager 类受到了束缚。 这个类的 equals 方法必须能够用自己与任何一个 Employee 对象进行比较, 而不考虑经理拥有的那部分特有信息! 猛然间会让人感觉instanceof 测试并不是完美无瑕。
某些开发者认为不应该利用 getClass 检测, 因为这样不符合置换原则有一个应用AbstractSet 类的 equals 方法的典型例子,它将检测两个集合是否有相同的元素。AbstractSet类有两个具体子类: TreeSet 和HashSet, 它们分别使用不同的算法实现查找集合元素的操作。无论集合采用何种方式实现,都需要拥有对任意两个集合进行比较的功能。
然而, 集合是相当特殊的一个例子, 应该将 AbstractSetequals 声明为 final , 这是因为没有任何一个子类需要重定义集合是否相等的语义(事实上,这个方法并没有被声明为 final。这样做, 可以让子类选择更加有效的算法对集合进行是否相等的检测)。
下面可以从两个截然不同的情况看一下这个问题:

  • 如果子类能够拥有自己的相等概念, 则对称性需求将强制采用 getClass 进行检测。
  • 如果由超类决定相等的概念,那么就可以使用 imtanceof进行检测, 这样可以在不同子类的对象之间进行相等的比较。

在雇员和经理的例子中, 只要对应的域相等, 就认为两个对象相等。如果两个 Manager对象所对应的姓名、 薪水和雇佣日期均相等, 而奖金不相等, 就认为它们是不相同的, 因此,可以使用 getClass 检测。
但是,假设使用雇员的 ID 作为相等的检测标准,并且这个相等的概念适用于所有的子类, 就可以使用 instanceof 进行检测, 并应该将 Employee.equals 声明为 final。

4 hashCode方法

散列码( hash code ) 是由对象导出的一个整型值。散列码是没有规律的。如果 x 和 y 是两个不同的对象, x.hashCode( ) 与 y.hashCode( ) 基本上不会相同。 在下表中列出几个通过调用 String 类的 hashCode 方法得到的散列码。
String 类使用下列算法计算散列码:

int hash = 0;
for (int i = 0; i < length0;i++)
hash = 31 * hash + charAt(i)

由于 hashCode方法定义在 Object 类中, 因此每个对象都有一个默认的散列码,其值为对象的存储地址。来看下面这个例子。

String s = "Ok";
StringBuilder sb = new StringBuilder(s);
System.out.println(s.hashCode() + " " + sb.hashCode());
String t = new String("Ok");
StringBuilder tb = new StringBuilder(t);
System.out.println(t.hashCode() + " "+ tb.hashCode());

在这里插入图片描述
请注意, 字符串 s 与 t 拥有相同的散列码, 这是因为字符串的散列码是由内容导出的。而字符串缓冲 sb 与 tb却有着不同的散列码, 这是因为在 StringBuffer 类中没有定义hashCode 方法,它的散列码是由 Object 类的默认 hashCode 方法导出的对象存储地址。
如果重新定义 equals方法,就必须重新定义 hashCode 方法, 以便用户可以将对象插入到散列表中。
hashCode 方法应该返回一个整型数值(也可以是负数), 并合理地组合实例域的散列码,以便能够让各个不同的对象产生的散列码更加均匀。
例如, 下面是 Employee 类的 hashCode 方法。

public class Employee
{
	public int hashCode()
	{
		return 7 * name.hashCode0
			+ 11 * new Double(salary).hashCode0
			+ 13 * hireDay.hashCode();
	}
	...
}

不过,还可以做得更好。首先, 最好使用 null 安全的方法Objects. hashCode。 如果其参数为 null,这个方法会返回 0, 否则返回对参数调用 hashCode 的结果。
另外,使用静态方法 Double.hashCode 来避免创建 Double 对象:

public int hashCode()
{
	return 7 * Objects.hashCode(name)
	+ 11 * Double.hashCode(salary)
	+ 13 * Objects.hashCode(hireDay);
}

还有更好的做法,需要组合多个散列值时,可以调用 Objects.hash 并提供多个参数。这个方法会对各个参数调用 Objects.hashCode, 并组合这些散列值。这样 Employee.hashCode 方法可以简单地写为:

public int hashCodeO
{
return Objects.hash(name, salary, hireDay);
}

equals 与 hashCode 的定义必须一致:如果 x.equals(y) 返回 true, 那么 x.hashCode( ) 就必须与 y.hashCode( ) 具有相同的值。例如,如果用定义的 Employee.equals 比较雇员的 ID,那么 hashCode 方法就需要散列 ID,而不是雇员的姓名或存储地址。

如果存在数组类型的域, 那么可以使用静态的 Arrays.hashCode 方法计算一个散列,这个散列码由数组元素的散列码组成。

5 toString方法

在 Object 中还有一个重要的方法, 就是 toString方法, 它用于返回表示对象值的字符串。下面是一个典型的例子。Point 类的 toString方法将返回下面这样的字符串:

java.awt.Point[x=10,y=20]

绝大多数(但不是全部)的 toString方法都遵循这样的格式:类的名字,随后是一对方括号括起来的域值。下面是 Employee 类中的 toString 方法的实现:

public String toStringO
{
return "Employee[name=" + name
+ ", salary=" + salary
+ ", hireDay=" + hireDay
}

toString方法也可以供子类调用。
当然,设计子类的程序员也应该定义自己的 toString 方法,并将子类域的描述添加进去。如果超类使用了 getClass( ).getName( ), 那么子类只要调用 super.toString( )就可以了。例如,下面是 Manager 类中的 toString 方法:

public class Manager extends Employee {
	public String toString {
		return super.toString() + "[bonus=" + bonus+ "]";
	}
}

现在,Manager 对象将打印输出如下所示的内容:

Manager[name=...,salary=...,hireDay=...][bonus=...]

随处可见 toString方法的主要原因是:只要对象与一个字符串通过操作符
“+” 连接起来,Java 编译就会自动地调用 toString方法,以便获得这个对象的字符串描述。例如:

Point p = new Point(10, 20);
String message = "The current position is " + p;

注:在调用 x.toString() 的地方可以用 “”+x 替代。这条语句将一个空串与 x 的字符串表示相连接。这里的 x 就是 x.toString() 。与 toString 不同的是,如果 x 是基本类型,这条语句照样能够执行

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

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

相关文章

医院陪诊小程序源码 陪诊陪护小程序源码

医院陪诊小程序源码 陪诊陪护小程序源码 近年来&#xff0c;随着互联网技术的不断发展&#xff0c;我们的生活中出现了越来越多的智能设备和智能应用&#xff0c;这些智能应用不仅极大方便了我们的生活&#xff0c;还对现代医疗服务体验产生了深远的影响。本文将为大家介绍一种…

轻松搭建Linux的环境

Linux的环境的搭建 目录&#xff1a;一、使用云服务器二、使用虚拟机软件2.1 下载虚拟机软件2.2 下载一个操作系统的镜像文件 三、直接安装在物理机上四、使用XShell远程登录到Linux 目录&#xff1a; 我们平常用的都是windows系统&#xff0c;对Linux系统还是很陌生得。为什么…

【软件测试】资深测试聊,自动化测试分层实践,彻底打通高阶...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 自动化测试的分层…

软件调研、研发、设计、管理、验收文档(全文档整理)

前言&#xff1a; 在软件开发生命周期中&#xff0c;调研、研发、设计、管理、验收等环节的文档编写至关重要。它们分别扮演着不同的角色&#xff0c;为项目的顺利进行和最终的成功提供支持和保障。 【获取方式在文末】 【在调研阶段】&#xff0c;文档的主要作用是记录和整…

Java环形链表(图文详解)

目录 一、判断链表中是否有环 &#xff08;1&#xff09;题目描述 &#xff08;2&#xff09;题解 二、环形链表的入环节点 &#xff08;1&#xff09;题目描述 &#xff08;2&#xff09;题解 一、判断链表中是否有环 &#xff08;1&#xff09;题目描述 给你一个链表的…

OCX 添加方法和事件 HTML调用ocx函数及回调 ocx又调用dll VS2017

ocx添加方法 类视图 最后面的XXXXXlib 右键 添加 添加方法。 其它默认 添加事件 类视图 最后面的XXXXX 右键 添加 添加事件。 这样编译就ocx可以了。 #include <iostream> #include <string> #include <comutil.h>CMFCActiveXControlSmartPosCtrl* …

Linux内核启动流程-第二阶段rest_init函数

一. Linux内核启动 上一篇文章简单了解了 Linux内核启动第二阶段&#xff0c;涉及的 start_kernel函数。start_kernel 函数最后调用了 rest_init 函数&#xff0c;接下来简单看一下 rest_init 函数。 本文续上一篇文章的学习&#xff0c;地址如下&#xff1a; Linux内核启…

W5500+树莓派RP2040入门教程之MQTT篇(十二)

目录 1 前言 2 什么是MQTT协议&#xff1f; 2.1 特点 2.2 应用 2.3 身份 2.4 消息质量等级 2.5 遗嘱消息 3 硬件介绍 4 硬件接线 5 代码编写 6 移植说明 7 最终现象 8 总结 9 项目链接 1 前言 随着物联网技术的快速发展&#xff0c;MQTT&#xff08;Message Queuing Telemetry …

微分算子法求解常系数线性微分方程特解

1.微分算子法求解常系数线性微分方程特解 参考资料&#xff1a;全网讲解最清楚的微分算子法&#xff01; 1.1 微分算子法的思路 1.2 f ( x ) e α x f(x)e^{\alpha x} f(x)eαx 型 1.3 f ( x ) sin ⁡ β x f(x)\sin\beta x f(x)sinβx 或 f ( x ) cos ⁡ β x f(x)\co…

oracle VM virtualbox 自动挂载共享目录

目标&#xff1a; 1 安装增强插件 2 设置共享目录 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a3ef43aa3a934e4691bad53874f6b427.png 3 修改fstab sudo chmod 777 /etc/fstab vi /etc/fstab 增加一行&#xff1a; pc /mnt/pc vboxsf defaults 0 0 例子&#xff1a…

tensor维度变换

作用函数不变大小改变shapeview / reshape删减与增加维度squeeze / unsqueeze维度扩展expand / repeat矩阵转置&#xff0c;单次和多次交换操作t / transpose / permute 1、 view reshape view与reshape效果一致&#xff0c;且可以通用。直接以view为例&#xff1a; a torc…

CH08_搬迁特性

搬迁函数&#xff08;Move Function&#xff09; 曾用名&#xff1a;搬迁函数&#xff08;Move Method&#xff09; class Account{get overdraftCharge(){...}... }class AccountType{get overdraftCharge(){...}... }动机 模块化是优秀软件设计的核心所在&#xff0c;好的模…

C语言自定义类型讲解:结构体,枚举,联合(2)

&#x1f435;本篇文章将会对位段、枚举和联合的相关知识进行讲解 1. 位段&#x1f4da; 1.1 什么是位段 位段的声明和结构体类似&#xff0c;但是有两点不同&#xff1a; 1.位段的成员必须是int&#xff0c;unsigned int&#xff0c;signed int (C99之后也可以是其他成员&am…

Redis 线程模式

Redis 是单线程吗&#xff1f; Redis 单线程指的是 [接收客户端请求 -> 解析请求 -> 进行数据读写操作 -> 发送数据给客户端] 这个过程是由一个线程 (主线程) 来完成的&#xff0c;这也是常说的 Redis 是单线程的原因。 但是 &#xff0c;Redis 程序不是单线程的&am…

nginx 反向代理 负载均衡 动静分离

一样东西的诞生通常都是为了解决某些问题&#xff0c;对于 Nginx 而言&#xff0c;也是如此。 比如&#xff0c;你出于无聊写了一个小网站&#xff0c;部署到 tomcat 之后可以正常访问 但是后来&#xff0c;你的这个小网站因为内容很诱人逐步的火了&#xff0c;用户越来越多&a…

C#开发的OpenRA游戏之雷达地图

C#开发的OpenRA游戏之雷达地图 从前面的游戏里,就可以看到在上面按钮下面留有一个区域,这个区域的作用,就是用来显示一个雷达地图,如下图所示: 从雷达地图来看,可以清楚地看到全局的动态,自己的兵力分布,还有自己的建筑分布,矿产分布等等。 在这里就来对这个雷达地图…

Python编程:使用PIL进行JPEG图像压缩的简易教程

摘要: 本文介绍了如何使用Python编程语言和wxPython图形用户界面库进行JPEG图像的压缩。通过添加滑块控件&#xff0c;我们可以调整压缩质量&#xff0c;并将压缩后的照片另存为原来的名称加上后缀"压缩质量数字"的新文件。 C:\pythoncode\new\image2small.py 完整…

AI编程助手 Amazon CodeWhisperer 全面解析与实践

目录 引言Amazon CodeWhisperer简介智能编程助手智能代码建议代码自动补全 提升代码质量代码质量提升安全性检测 支持多平台多语言 用户体验和系统兼容性用户体验文档和学习资源个性化体验系统兼容性 功能全面性和代码质量功能全面性代码生成质量和代码安全性 CodeWhisperer的代…

程序启动-大数据平台搭建

1、启动zookeeper集群 /home/cluster/zookeeper.sh start /home/cluster/zookeeper.sh stop 2、启动hadoop和yarn集群 /home/cluster/hadoop-3.3.6/sbin/start-dfs.sh /home/cluster/hadoop-3.3.6/sbin/start-yarn.sh /home/cluster/hadoop-3.3.6/sbin/stop-dfs.sh /home/clust…

以太坊代币标准ERC20、ERC165、ERC721

两个概念 ERC(Ethereum Request for Comment) 以太坊意见征集稿EIP(Ethereum Improvement Proposals)以太坊改进提案 ERC和EIP用于使得以太坊更加完善&#xff1b;在ERC中提出了很多标准&#xff0c;用的最多的标准就是它的Token标准; 有哪些标准详细见https://eips.ethereum…