一文详解java中的==和equals()

这篇具有很好参考价值的文章主要介绍了一文详解java中的==和equals()。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、"=="运算符

二、"equals()"方法

三、举例说明和解释

3.1、例子

3.2、基本数据类型的比较

3.3、引用数据类型的比较

    3.3.1 String类

    3.3.2 未重写equals方法的类

四、为什么重写equals方法就一定要重写hashCode方法 

4.1 为什么要重写equals方法

4.2 hashCode

4.3 为什么equas和hashCode要一起重写?

        4.3.1 Set集合正常使用

        4.3.2  Set集合的"异常"使用

4.4 原因分析 

4.5 总结

五、练手举例


"=="和equals 最大的区别是
    1."=="是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。
    2.equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。

一、"=="运算符

   1.如果比较的对象是基本数据类型,则比较的是其存储的值是否相等;

   2.如果比较的是引用数据类型,则比较的是所指向对象的地址值是否相等(是否是同一个对象)。

二、"equals()"方法

        equals是Object的方法,用来比较两个对象的地址值是否相等。

        方法如下:

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

注意:
equals 方法不能用于比较基本数据类型,如果没有对 equals 方法进行重写,则相当于“==”,比较的是引用类型的变
所指向的对象的地址值。 

    一般情况下,类会重写equals方法用来比较两个对象的内容是否相等。比如String类中的equals()是被重写了,比较的是对象的值

三、举例说明和解释
3.1、例子

public static void main(String[] args) {
        //基本数据类型的比较
        int num1 = 10;
        int num2 = 10;
        System.out.println(num1 == num2);   //true

        //引用数据类型的比较
        //String类(重写了equals方法)中==与equals的比较
        
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);    //true,比较地址值:内容相同,因为常量池中只有一个“hello”,所以它们的地址值相同
        System.out.println(s1.equals(s2));//true,比较内容:内容相同,因为常量池中只有一个“hello”,所以它们的地址值相同
        System.out.println(s1.equals("hello")); //true

       
        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println(s3 == s4);        //false,比较地址值:s3和s4在堆内存中的地址值不同
        System.out.println(s3.equals(s4));    //true,比较内容:内容相同

        //没有重写equals方法的类中==与equals的比较 
        People p1 = new People();
        People p2 = new People();
        People p = p2;
        System.out.println(p1);//People@135fbaa4
        System.out.println(p2);//People@45ee12a7
        System.out.println(p); //People@45ee12a7
        System.out.println(p1.equals(p2));       //false,p1和p2的地址值不同
        System.out.println(p.equals(p2));        //true,p和p2的地址值相同
    }
 

3.2、基本数据类型的比较

"=="正常比较其值。equals不用于基本数据类型的比较。

3.3、引用数据类型的比较
    3.3.1 String类

     String类对equals()方法进行了重写。

     1.创建字符串对象一般有如下两种写法:

    String s1 = "hello";//在字符串常量池中创建"hello",并将地址值赋值给s1。
    String s2 = new String("world");//通过new关键字在堆中创建对象,并将对象地址值赋值给s2。

      •  对于String s2 = new String(“world”);
            首先在堆内存中申请内存存储String类型的对象,将地址值赋给s2;
            在方法区的常量池中找,有无hello:
            若没有,则在常量池中开辟空间存储hello,并将该空间的地址值赋给堆中存储对象的空间;
            若有,则直接将hello所在空间的地址值给堆中存储对象的空间。

      •  对于String s1 = “hello”;
            在方法区的常量池中找,有无hello,如果没有,就在常量池中开辟空间存储hello。
            然后只需要将hello所在空间的地址值赋给 s1。

字符串作为最基础的数据类型,使用非常频繁,如果每次都通过 new 关键字进行创建,会耗费高昂的时间和空间代价。Java 虚拟机为了提高性能和减少内存开销,就设计了字符串常量池. 在JDK1.7之前字符串常量池是存储在方法区的。JDK1.7之后存储在堆中了。

      2.String类对equals的重写如下:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof 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;
    }

代码解释

       • 若当前对象和比较的对象是同一个对象,即return true。也就是Object中的equals方法。
       • 若当前传入的对象是String类型,则比较两个字符串的长度,即value.length的长度。
       • 若长度不相同,则return false。
       • 若长度相同,则按照数组value中的每一位进行比较。若不同,则返回false。若每一位都相同,则返回true。
       • 若当前传入的对象不是String类型,则直接返回false。
       • 此外StringBuffer和StringBuilder并没有重写equals方法,其比较的还是引用类型的地址。

    3.3.2 未重写equals方法的类

        如果类没有重写equals方法,其比较的还是引用类型的地址。

四、为什么重写equals方法就一定要重写hashCode方法 

先放结论:

hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度。
如果只重写equals方法,不重写hashCode方法,就有可能导致a.equals(b)这个表达式成立,但是hashCode却不同。会造成一个完全相同的对象会存储在hash表的不同位置。

4.1 为什么要重写equals方法

Object 类中的 equals 方法用于检测一个对象是否等于另外一个对象。在 Object 类中,这个方法将判断两个对象是否具有相同的引用。如果两个对象具有相同的引用,它们一定是相等的。​大多数情况下不重写equals方法,直接使用Object中的equals方法是没有任何意义的,不如直接使用==运算符,二者是等价的。

以下代码示例,就可以说明这个问题: 

package com.hulei.studyproject.blogtest;

import lombok.Getter;

/**
 * @Title: EqualsMyClassExample
 * @Description: TODO
 * @author: hulei
 * @date: 2023/8/4 13:52
 * @Version: 1.0
 */

public class EqualsMyClassExample {
    public static void main(String[] args) {
        Person u1 = new Person();
        u1.setName("Java");
        u1.setAge(18);

        Person u2 = new Person();
        u2.setName("Java");
        u2.setAge(18);

        System.out.println(u1.equals(u2));
    }
}

@Getter
class Person{
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

输出结果如下图所示:

java==和equals,java,开发语言

可以看到两个不同的引用,不重写equals,直接调用Object类中的原始equals方法,比较结果一定是false,这种比较没有意义,因为内存地址不同,即使两个对象的内容完全相同,因此通常情况下,我们要判断两个对象是否相等,一定要重写 equals 方法,这就是为什么要重写 equals 方法的原因。

4.2 hashCode

hashCode 翻译为中文是散列码,它是由对象推导出的一个整型值,并且这个值为任意整数,包括正数或负数。​

需要注意的是:散列码是没有规律的。

     如果 x 和 y 是两个不同的对象,x.hashCode() 与 y.hashCode() 基本上不会相同;但是也有例外
    • 但如果 a 和 b 相等,则 a.hashCode() 一定等于 b.hashCode()。​

hashCode使用

package com.hulei.studyproject.blogtest;

/**
 * @Title: EqualsMyClassExample
 * @Description: TODO
 * @author: hulei
 * @date: 2023/8/4 13:52
 * @Version: 1.0
 */

public class EqualsMyClassExample {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = "Java";
        System.out.println("s1 hashCode" + s1.hashCode());
        System.out.println("s2 hashCode" + s2.hashCode());
        System.out.println("s3 hashCode" + s3.hashCode());

        // 在一些特殊情况下是相同的
        String t1 = "Aa";
        String t2 = "BB";
        System.out.println("t1 hashCode" + t1.hashCode());
        System.out.println("t2 hashCode" + t2.hashCode());
    }
}

结果如下:

java==和equals,java,开发语言

在java中,equals和hashcode是有设计要求的,equals相等,则hashcode一定相等,反之则不然。 为何会有这样的要求? 在集合中,比如HashSet中,要求放入的对象不能重复,怎么判定呢? 首先会调用hashode,如果hashcode相等,则继续调用equals。

4.3 为什么equas和hashCode要一起重写?

下面看几个示例:

        4.3.1 Set集合正常使用
package com.hulei.studyproject.blogtest;

import java.util.HashSet;
import java.util.Set;

/**
 * @Title: EqualsMyClassExample
 * @Description: TODO
 * @author: hulei
 * @date: 2023/8/4 13:52
 * @Version: 1.0
 */

public class EqualsMyClassExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet();
        set.add("Java");
        set.add("Java");
        set.add("MySQL");
        set.add("MySQL");
        set.add("Redis");
        System.out.println("Set 集合长度:" + set.size());
        System.out.println();
        // 打印 Set 中的所有元素
        set.forEach(System.out::println);
    }
}

 执行结果如下:

java==和equals,java,开发语言

从上述结果可以看出,重复的数据已经被 Set 集合"合并"了,这也是 Set 集合最大的特点:去重

       4.3.2  Set集合的"异常"使用

重写equals方法

package com.hulei.studyproject.blogtest;

import lombok.Getter;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * @Title: EqualsMyClassExample
 * @Description: TODO
 * @author: hulei
 * @date: 2023/8/4 13:52
 * @Version: 1.0
 */

public class EqualsMyClassExample {
    public static void main(String[] args) {
        Person u1 = new Person();
        u1.setName("Java");
        u1.setAge(18);

        Person u2 = new Person();
        u2.setName("Java");
        u2.setAge(18);

        System.out.println("equals result = " + u1.equals(u2));

        // 创建 Set 集合
        Set<Person> set = new HashSet<>();
        set.add(u1);
        set.add(u2);
        // 打印 Set 中的所有数据
        set.forEach(System.out::println);
    }
}
@Getter
class Person{
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public 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);
    }

    /*@Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }*/

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

 执行结果如下所示:

java==和equals,java,开发语言

这就造成了equals比较结果明明是相同值,为什么Set却重复存储呢? 

再放开代码中重写的hashCode方法注释,执行结果如下所示:

java==和equals,java,开发语言

此时可以看到Set集合进行了去重。

4.4 原因分析 

默认情况下,Set 进行去重操作时,会先判断两个对象的 hashCode 是否相同,此时因为没有重写 hashCode 方法,所以会直接执行 Object 中的 hashCode 方法,而 Object 中的 hashCode 方法对比的是两个不同引用地址的对象,所以结果是 false,那么 equals 方法就不用执行了,直接返回的结果就是 false:两个对象不是相等的,于是就在 Set 集合中插入了两个相同的对象。​

但是,如果在重写 equals 方法时,也重写了 hashCode 方法,那么在执行判断时会去执行重写的 hashCode 方法,此时对比的是两个对象的所有属性的 hashCode 是否相同,于是调用 hashCode 返回的结果就是 true,再去调用 equals 方法,发现两个对象确实是相等的,于是就返回 true 了,因此 Set 集合就不会存储两个一模一样的数据了,于是整个程序的执行就正常了。

4.5 总结

      • hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度。
      • 如果只重写equals方法,不重写hashCode方法,就有可能导致a.equals(b)这个表达式成立,但是hashCode却不同。会造成一个完全相同的对象会存储在hash表的不同位置。

五、练手举例

1.下面的代码将创建几个字符串对象?3个 

String s1 = new String(“Hello”);
String s2 = new String(“Hello”);

分别创建了s1堆内存上的实例,s2内存上的实例,以及字符串常量池

 2.在java中,String s=new String(“xyz”)创建了几个对象?C

A 1个 B 1个或2个 C 2个 D 以上都不对

3.下面的代码输出什么?

String s1 = new String(“abc”);
String s2 = new String(“abc”);
System.out.println(s1 == s2);//false
System.out.println(s1.equals(s2)); // true

4.下面的代码输入什么? 

String s1 = "abc";
String s2 = new String("abc");

//可以拿到s2的常量
s2.intern();
System.out.println(s1 ==s2);//false

5.下面的代码输出什么?

String s1= "abc";
String s2= "abc";
String s3 = new String("abc");  
String s4 = new String("abc"); 

System.out.println("s3 == s4 : "+(s3==s4)); //false
System.out.println("s3.equals(s4) : "+(s3.equals(s4)));  //true
System.out.println("s1 == s3 : "+(s1==s3));  //false
System.out.println("s1.equals(s3) : "+(s1.equals(s3))); //true
System.out.println(s1==s2); //true

6.下面的代码输出什么?

String str1 = “ab” + “cd”;
String str11 = “abcd”;
System.out.println("str1 = str11 : "+ (str1 == str11)); //true

7.下面的代码输出什么?

String str2 = “ab”;
String str3 = “cd”;
String str4 = str2+str3;
String str5 = “abcd”;
System.out.println("str4 = str5 : " + (str4==str5));//false!

8.下面的代码输出什么?

final String str2 = “ab”;
final String str3 = “cd”;
String str4 = str2+str3;
String str5 = “abcd”;
System.out.println("str4 = str5 : " + (str4==str5));//true

9.下面的代码输入什么?

String str6 = “b”;
String str7 = “a” + str6;
String str67 = “ab”;
System.out.println("str7 = str67 : "+ (str7 == str67)); //false

10.下面的代码输入什么?

final String str8 = “b”;
String str9 = “a” + str8;
String str89 = “ab”;
System.out.println("str9 = str89 : "+ (str9 == str89)); //true

11.下面选项结果为true的是:C

String s1="Hello";
String s2="hello";
String s3=s1.toLowerCase();
String s4=s2.toLowerCase();

A.S1==s3    
B.S2==s3
C.S2==s4    
D.S3==s4文章来源地址https://www.toymoban.com/news/detail-756916.html

到了这里,关于一文详解java中的==和equals()的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java中equals详解

    equals是在object类中的方法,在object中equals是用来看看 两个参数是否引用的是同一个对象 例: obj.equals(obj2) 若是返回true说明两者引用同一个对象 源码: 但是在我们实际开发中经常比较的是 两个对象的内容是否相等 ,因此就要重写equals,注意只能是 一个类里比 说到equals不得

    2023年04月08日
    浏览(10)
  • java equals与equalsignorecase详解

    Java中的equals()方法用于比较两个对象是否相等,它在Object类中定义,通常需要在子类中进行重写以实现特定的行为。equalsIgnoreCase()方法也是用于比较字符串是否相等,但不考虑大小写,即它会忽略字符串中字符的大小写差异。 equals()方法的默认实现是检查两个对象的引用是否

    2024年02月15日
    浏览(10)
  • 编程开发8大语言详解,为什么Java是我最推荐的?

    编程开发8大语言详解,为什么Java是我最推荐的?

    很多没有接触过编程语言的同学,都会觉得编程开发特别高端和神奇,担心理解不了更担心学不会。 当然,也有人会认为,你既然是做编程的,那么你应该什么都会,什么软件的开发都能完成,这是平哥经常听到的两种声音。 在此,平哥需要给大家科普一下, 编程确实改变

    2024年02月05日
    浏览(11)
  • Java开发手册中为什么禁止使用BigDecimal的equals方法做等值比较已经为什么禁止使用double直接构造BigDecimal

    Java开发手册中为什么禁止使用BigDecimal的equals方法做等值比较已经为什么禁止使用double直接构造BigDecimal

    阿里Java开发手册嵩山版中明确指出: 1、BigDecimal的等值比较应使用compareTo()方法,而不是equals()方法 equals()方法会比较值和精度(1.0与1.00返回结果为false),而compareTo()则会忽略精度 2、禁止使用构造方法BigDecimal(double)的方式把double值转换为BigDecimal对象 BigDecimal(double)存在精度损

    2024年02月07日
    浏览(14)
  • 一文详解Pytorch中的Tensor操作

    一文详解Pytorch中的Tensor操作

    Tensor的英文原义是张量,PyTorch官网对其的定义如下: 也就是说,一个Tensor是一个包含单一数据类型的多维矩阵。通常,其多维特性用三维及以上的矩阵来描述,例如下图所示:单个元素为标量(scalar),一个序列为向量(vector),多个序列组成的平面为矩阵(matrix),多个平面组成

    2024年02月05日
    浏览(11)
  • 一文详解python中的数据库操作

    一文详解python中的数据库操作

    最近做毕设,需要添加个数据库,记录一下。 重点介绍数据库API接口中的连接对象和游标对象 1. 连接对象 数据库连接对象主要提供获取数据库游标对象和提交/回滚事务的方法,以及关闭数据库连接。 使用connect函数获取对象,该函数有多个参数: host 主机名 database/db 数据库

    2024年02月07日
    浏览(9)
  • 一文详解docker中的depends-on用法

    一文详解docker中的depends-on用法

    Docker 的 depends-on 指令用于指定一个容器依赖于另一个容器。当 depends-on 指令被使用时,Docker 将不会启动依赖的容器,直到被依赖的容器启动并运行成功。 在Docker Compose文件中,可以使用“depends-on”来定义服务之间的依赖关系。它的语法如下: 在上面的示例中,“se

    2024年03月12日
    浏览(10)
  • 一文详解 Sa-Token 中的 SaSession 对象

    Sa-Token 是一个轻量级 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。 Gitee 开源地址:https://gitee.com/dromara/sa-token 本文将详细介绍 Sa-Token 中的不同 SaSession 对象的区别,以及各种方便的存取值的方法。 Session 是会话

    2024年02月06日
    浏览(13)
  • 【Py/Java/C++三种语言详解】LeetCode每日一题240109【动态规划】LeetCode2707题、字符串中的额外字符

    给你一个下标从 0 开始的字符串 s 和一个单词字典 dictionary 。你需要将 s 分割成若干个 互不重叠 的子字符串,每个子字符串都在 dictionary 中出现过。 s 中可能会有一些 额外的字符 不在任何子字符串中。 请你采取最优策略分割 s ,使剩下的字符 最少 。 示例 1: 输入 :s =

    2024年01月16日
    浏览(16)
  • 【Spring进阶系列丨最终篇】一文详解Spring中的事务控制

    【Spring进阶系列丨最终篇】一文详解Spring中的事务控制

    本篇文章是【Spring进阶系列】专栏的最后一篇文章,至此,我们对Spring的学习就告一段落,接下来我会持续更新【 Spring+SpringMVC+MyBatis整合 】专栏,欢迎免费订阅! 事务需要放在业务层(service) Spring的事务是基于AOP的 Spring的事务控制有两种:编程式事务【了解】和 声明式事务

    2024年04月25日
    浏览(17)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包