• java中equals与==的用法浅析


    说到java中的equals与==的用法,这里首先梳理一下java中的数据类型,主要分为两大类:值类型引用类型,值类型也就是基本数据类型,而引用类型就是除了值类型之外的其他类型。

    • 基本数据类型(8种):byte、short、int、long、float、double、char、boolean
    • 引用类型(3种):类(Class)类型、接口(Interface)类型、数组(Array)类型

    1.equals用法总结

    个人的归纳如下:

    • 在Object类中定义了一个原始的equals方法,这个方法的行为是比较引用变量中存储的对象在堆内存中的地址,使用“==”实现。
    • 在一些类库当中equals方法被重写了,如String、包装类、Date等等。在这些类当中equals有其自身的实现,而不再是比较对象在堆内存中的存放地址了。 
    • 对于引用类型之间进行equals比较,在没有重写equals方法的情况下,他们之间的比较还是堆内存中的存放的地址值,跟双等号(“==”)的结果相同;如果被重写,则按照重写的要求来进行比较。
    • equals方法不能用于基本数据类型的比较,但是能够用于基本类型的包装类,并且比较的是对象的内容而不是地址。

    下面给出一些源码来进一步理解:

     1     //Object类中的equals方法
     2     public boolean equals(Object obj) {
     3         return (this == obj);
     4     }
     5 
     6     //String类中的equals方法,重写了Object类的equals方法
     7     public boolean equals(Object anObject) {
     8         if (this == anObject) {
     9             return true;
    10         }
    11         if (anObject instanceof String) {
    12             String anotherString = (String)anObject;
    13             int n = value.length;
    14             if (n == anotherString.value.length) {
    15                 char v1[] = value;
    16                 char v2[] = anotherString.value;
    17                 int i = 0;
    18                 while (n-- != 0) {
    19                     if (v1[i] != v2[i])
    20                         return false;
    21                     i++;
    22                 }
    23                 return true;
    24             }
    25         }
    26         return false;
    27     }
    28 
    29     //Integer类中的equals方法,重写了Object类的equals方法,其他包装类也重写了equals方法
    30     public boolean equals(Object obj) {
    31         if (obj instanceof Integer) {
    32             return value == ((Integer)obj).intValue();
    33         }
    34         return false;
    35     }
    36 
    37     //Date类中的equals方法,重写了Object类的equals方法
    38     public boolean equals(Object obj) {
    39         return obj instanceof Date && getTime() == ((Date) obj).getTime();
    40     }

     因此,当且仅当调用的是Object类的equals方法时,equals与“==”的作用相同,比较的是对象在堆内存中的地址;而当调用的是其他类重写过后的equals方法时,通常来说比较的是对象的内容而不是地址。具体示例如下:

     1         /*
     2          * StringBuffer和StringBuilder类都没有重写equals方法
     3          *     所以此处调用的是Object类的equals方法,比较的是地址
     4          */
     5         StringBuffer buffer1 = new StringBuffer("hello");
     6         StringBuffer buffer2 = new StringBuffer("hello");
     7         System.out.println(buffer1.equals(buffer2));//false
     8         System.out.println(buffer1 == buffer2);//false
     9 
    10         /*
    11          * String类重写了Object类的equals方法
    12          *     所以此处调用的是String类的equals方法,比较的是内容
    13          */
    14         String s1 = "hello";
    15         String s2 = "hello";
    16         String s3 = new String("hello");
    17         String s4 = new String("hello");
    18         System.out.println(s1.equals(s2));//true
    19         System.out.println(s1.equals(s3));//true
    20         System.out.println(s3.equals(s4));//true
    21 
    22         /*
    23          * Integer包装类重写了Object类的equals方法
    24          *     所以此处调用的是Integer类的equals方法,比较的是内容
    25          */
    26         Integer integer = new Integer(100);
    27         System.out.println(integer.equals(new Integer(100)));//true
    View Code

    2.==用法总结

    双等号(“==”)是一种关系运算符,它的用法比较简单,主要分为两种情况:

    • 用于基本数据类型之间的比较:比较的是变量的值(注意此时不一定要求“==”左右两边数据类型严格一致)
    • 用于引用类型之间的比较:比较的是引用对象在堆内存中的地址

    这里简单举了几个例子:

     1         //基本数据类型的比较
     2         int a=10, b=10;
     3         char ch1='A', ch2='A';
     4         System.out.println(a == b);//true
     5         System.out.println(ch1 == ch2);//true
     6         
     7         //引用类型的比较
     8         Object o1 = new Object();
     9         Object o2 = new Object();
    10         Object o3 = o1;
    11         System.out.println(o1 == o2);//false
    12         System.out.println(o1 == o3);//true
     1         int c = 65;
     2         float d = 65.0f;
     3         char ch = 'A';
     4 
     5         /*
     6          * 用于基本数据类型之间,比较的是变量的值
     7          *     注意:此时不一定要求数据类型严格一致
     8          */
     9         System.out.println(c == d);//true
    10         System.out.println(c == ch);//true
    11         System.out.println((d == ch));//true

     3.对比分析

    我们常常弄不明白equals与==的用法,是因为我们没有结合JDK源码系统地总结过它们,这里先抛出一段代码:

     1         String s1 = "hello";
     2         String s2 = "hello";
     3         String s3 = new String("hello");
     4         String s4 = new String("hello");
     5         System.out.println(s1.equals(s2));//true
     6         System.out.println(s1 == s2);//true
     7         
     8         System.out.println(s1.equals(s3));//true
     9         System.out.println(s1 == s3);//false
    10         
    11         System.out.println(s3.equals(s4));//true
    12         System.out.println(s3 == s4);//false

    有了之前的一些学习,我们来分析一下这段代码:

    • 由于这里的对象都是String类型,所以调用的都是String类的equals方法,比较的是字符串的内容,所以结果都是true。
    • 然而,代码的第6行中,“==”比较的是两个引用变量s1和s2所指向的对象的地址,结果为true;而第12行,这里的“==”比较的也是两个引用变量s3和s4所指向的对象的地址,结果为false。

    那么为什么第6行和第12行的结果不相同呢?

     这就涉及到字符串常量的两种创建方式“String s1 = "hello"”和“String s3 = new String("hello")”的区别了,这里用一个图来说明:

    通过上图,我们对于这两种字符串常量的创建方式可以总结如下:

    • 通过“String s1 = "hello"”方式创建的话,JVM要先检查常量池中是否已经包含有“hello”,若有,则将其地址赋给s1;否则将字符串常量“hello”存储在常量池中,并返回存储地址;
    • 通过“String s3 = new String("hello")”创建,JVM需要先在堆中开辟一段空间用于存储new出来的对象,又由于“hello”是一个字符串常量,所以需要将其放在常量池中,并返回其存储地址。

    因此,对于代码中第6行的“s1 == s2”,由于s1与s2都指向的是字符串常量池中“hello”的地址,所以结果为true;而对于第12行的“s3 == s4”,由于s3与s4指向的是堆中的两个不同的对象,所以结果为false。

  • 相关阅读:
    进程与线程
    Socket函数编程(二)
    socket编程
    subprocess 模块
    异常处理
    模块与包
    【Java基础】String源码分析
    【MySQL】 执行计划详解
    【MySQL】performance schema详解
    【Spring Cloud-Open Feign】使用OpenFeign完成声明式服务调用
  • 原文地址:https://www.cnblogs.com/Wilange/p/7684021.html
Copyright © 2020-2023  润新知