Java基础:equals()方法与==的区别

server/2025/1/12 7:09:34/
1、超类Object的equals()底层原理:

在Object超类中已经提供了equals()方法,源码如下:

public boolean equals(Object obj) {   return (this == obj);     }

所有的对象都拥有标识(内存地址)和状态(数据),同时“==”比较的是两个对象的内存地址,在Object的equals()底层调用的是==号,所以说Object的equals()是比较两个对象的内存地址是否相等,如果为true,则表示的引用的是同一个对象。

2、equals()与 == 的区别:

(1)== 号在比较基本数据类型时比较的是数据的值,而比较引用类型时比较的是两个对象的地址值;

(2)equals()不能用于基本的数据类型,对于基本的数据类型要用其包装类。

(3)默认情况下,从Object继承而来的 equals 方法与 “==” 是完全等价的,比较的都是对象的内存地址,因为底层调用的是 “==” 号,但我们可以重写equals方法,使其按照我们的需求方式进行比较,如String类重写equals()方法,使其比较的是字符的内容,而不再是内存地址。

String类重写的equals源码如下:

public boolean equals(Object anObject) {//判断调用equals方法的对象和 形参引用地址是否相等if (this == anObject) {return true;}//判断左边形参引用是否是右边String类的实例对象if (anObject instanceof String) {//将形参引用强制转换为String对象String anotherString = (String)anObject;//获取字符串长度int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}

 3、equals()的重写规则:

  • 自反性。对于任何非null的引用值x,x.equals(x)应返回true。
  • 对称性。对于任何非null的引用值x与y,当且仅当:y.equals(x)返回true时,x.equals(y)才返回true。
  • 传递性。对于任何非null的引用值x、y与z,如果y.equals(x)返回true,y.equals(z)返回true,那么x.equals(z)也应返回true。
  • 一致性。对于任何非null的引用值x与y,假设对象上equals比较中的信息没有被修改,则多次调用x.equals(y)始终返回true或者始终返回false。
  • 对于任何非空引用值x,x.equal(null)应返回false。

4、有关equals()与 == 号的小例子: 

public class Test {public static void main(String[] args) {	String str1 = new String("abc");String str2 = new String("abc");System.out.println(str1 == str2);//falseSystem.out.println(str1.equals(str2));//trueString str3 = "123";String str4 = "123";System.out.println(str3 == str4);//trueSystem.out.println(str3.equals(str4));//true	}
}

 在上述代码中,str1和str2都是new String()的对象,所以尽管()中的字符串值一样,但仍然是两个不同的对象,所以str1==str2比较对象地址不同,为false。而string的equals比较的是字符串值,所以str1.equals(str2)为true。而str3和str4都是在堆中创建了同一个字符串对象“123”,指向的都是字符串常量池中的“123”,所以str3==str4为true。

5、重写equals()中 getClass 与 instaceof 的区别:

在重写equals() 方法时,一般都是推荐使用 getClass 来进行类型判断,不是使用 instanceof(除非所有的子类有统一的语义才使用instanceof)。我们都知道 instanceof 的作用是判断其左边对象是否为其右边类的实例,返回 boolean 类型的数据,可以用来判断继承中的子类的实例是否为父类的实现。

下来我们来看一个例子:父类Person

public class Person {protected String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public Person(String name){this.name = name;}public boolean equals(Object object){if(object instanceof Person){Person p = (Person) object;if(p.getName() == null || name == null){return false;}else{return name.equalsIgnoreCase(p.getName ());}}return false;}}

 子类 Employee:

public class Employee extends Person{private int id;public int getId() {return id;}public void setId(int id) {this.id = id;}public Employee(String name,int id){super(name);this.id = id;}/*** 重写equals()方法*/public boolean equals(Object object){if(object instanceof Employee){Employee e = (Employee) object;return super.equals(object) && e.getId() == id;}return false;}}

上面父类 Person 和子类 Employee 都重写了 equals(),不过 Employee 比父类多了一个id属性,而且这里我们并没有统一语义。测试代码如下:

public class Test {public static void main(String[] args) {Employee e1 = new Employee("employee", 23);Employee e2 = new Employee("employee", 24);Person p1 = new Person("employee");System.out.println(p1.equals(e1));//trueSystem.out.println(p1.equals(e2));//trueSystem.out.println(e1.equals(e2));//false}}

上面代码我们定义了两个员工和一个普通人,虽然他们同名,但是他们肯定不是同一人,所以按理来说结果应该全部是 false,但是事与愿违,结果是:true、true、false。对于那 e1!=e2 我们非常容易理解,因为他们不仅需要比较 name,还需要比较 ID。但是 p1 即等于 e1 也等于 e2,这是非常奇怪的,因为 e1、e2 明明是两个不同的类,但为什么会出现这个情况?首先 p1.equals(e1),是调用 p1 的 equals 方法,该方法使用 instanceof 关键字来检查 e1 是否为 Person 类,这里我们再看看 instanceof:判断其左边对象是否为其右边类的实例,也可以用来判断继承中的子类的实例是否为父类的实现。他们两者存在继承关系,肯定会返回 true 了,而两者 name 又相同,所以结果肯定是 true。所以出现上面的情况就是使用了关键字 instanceof,这是非常容易导致我们“钻牛角尖”。故在覆写 equals 时推荐使用 getClass 进行类型判断。而不是使用 instanceof(除非子类拥有统一的语义)。


http://www.ppmy.cn/server/157689.html

相关文章

Java Web开发进阶——Spring Security基础与应用

Spring Security是Spring框架的核心模块之一,用于保护Web应用程序和微服务的安全。它提供强大的认证和授权功能,并与Spring生态系统无缝集成。本节将详细介绍Spring Security的基础知识及其在实际项目中的应用。 1. Spring Security概述与功能 1.1 什么…

微信小程序实现拖拽盒子效果

要实现一个当前盒子高度由里面的盒子进行支配高度拖拽的效果 // wxml<view class"exmation-item" wx:elif"{{type4}}"> <view class"exmation-item-drag-box" id"drag-box"> <!-- 内容 --><view class"exm…

Scala语言的软件开发工具

Scala语言的软件开发工具 Scala是一种静态类型的编程语言&#xff0c;它结合了面向对象和函数式编程的特性。自2003年由马丁奥德斯基&#xff08;Martin Odersky&#xff09;发明以来&#xff0c;Scala因其简洁的语法和强大的功能&#xff0c;逐渐成为了现代软件开发领域的重要…

Web前端开发入门学习笔记之CSS 57-58--新手超级友好版- 盒子模型以及边框线应用篇

Foreword写在前面的话&#xff1a; 大家好&#xff0c;我是一名刚开始学习HTML的新手。这篇文章是我在学习html过程中的一些笔记和心得&#xff0c;希望能和同样在学习HTML的朋友们分享。由于我的知识有限&#xff0c;文章中可能存在错误或不准确的地方&#xff0c;欢迎大家在评…

SpringBoot开发—— SpringBoot中如何实现 HTTP 请求的线程隔离

文章目录 1、Servlet 容器与线程池管理1.1 线程池的作用1.2 线程池的配置 2、HTTP 请求的线程隔离2.1 请求上下文和会话信息2.2 多线程处理的隔离性 3、 ThreadLocal 和线程上下文隔离3.1ThreadLocal的使用3.2 保证线程隔离性 4、Async异步任务的线程隔离4.1 异步任务的线程池4…

【Redis入门到精通六】在Spring Boot中集成Redis(含配置和操作演示)

目录 Spring Boot中集成Redis 1.项目创建和环境配置 2.基本操作演示 Spring Boot中集成Redis Spring社区也自定义了一套Redis的客户端&#xff0c;与jedis的操作方式有所差异&#xff0c;Spring中把每个类型的操作都单独封装了起来。下面就让我来带大家了解如何在Spring Bo…

python批量删除redis key

生产环境中要禁止使用keys *查询key, 因为redis低版本是单线程&#xff0c;如果key非常多的话&#xff0c;直接使用keys *会导致阻塞&#xff0c;所以应当使用scan命令&#xff0c;scan命令介绍请参考其他文档。 # -*- coding: utf-8 -*- # Time : 2025/01/09 # Author : 养…

常见的http状态码 + ResponseEntity

常见的http状态码 ResponseStatus(HttpStatus.CREATED) 是 Spring Framework 中的注解&#xff0c;用于指定 HTTP 响应状态码。 1. 基本说明 HttpStatus.CREATED 对应 HTTP 状态码 201表示请求成功且创建了新的资源通常用于 POST 请求的处理方法上 2. 使用场景和示例 基本…