java中`==`和`equals`的分析

java中==equals的分析

1.java中==equals()方法介绍

  • ==一般用来比较两个基本数据类型变量(局部变量)的值是否相等。如果用于比较引用数据类型的变量,也是比较变量的值,不同的是,引用数据类型变量存储的是数据的首地址(即数据在堆中存放的地址),所以是地址的比较。

    • Java中的8种基本数据类型:
      • 整型4种:byte(1字节),short(2字节),int(4字节),long(8字节)
      • 浮点型2种:float(4字节),double(8字节)
      • 字符型1种:char(2字节)
      • 布尔型1种:boolean(1bit)
    • Java中的引用数据类型:
      • 类(包含String)
      • 接口
      • 数组
  • equals()方法一般用于两个对象的内容是否相等。内容即变量所存储的地址指向的数据,在堆中。

    • 例如:比较String类的对象String str1 = new String("happy")String str2 = new String("happy")是否相等
    • ==比较str1str2的结果是false,用equals()方法比较结果是true。

2.Java中的数据类型在内存中的存储原理

  • 在方法中声明的变量,称为局部变量;在类中声明的变量是成员变量,也叫全局变量。

    • 对于局部变量来说,不论是基本数据类型还是引用类型,他们都会先在栈中分配一块内存,对于基本类型来说,这块区域包含的是基本类型的内容;而对于引用类型来说,这块区域包含的是指向真正内容的指针,真正的内容被手动的分配在堆上。
    • 对于成员变量来说,不论是基本数据类型还是引用类型,他们都会存储在堆内存或者方法区中;成员变量可细分为静态成员变量和普通成员变量,静态成员变量属于类,类可以直接访问,存储在方法区中;普通成员变量属于类对象,必须声明对象之后,通过对象才能访问,存储在堆中。

3.java中==equals()适用范围举例分析

3.1 比较java基本数据类型

  • 比较java基本数据类型:

    • 对于8种基本数据类型(byte,short,char,int,float,double,long,boolean)

    • 只能用==,不能用equals()(单纯的变量也无法调用equals()方法),这里的==比较的是两个基本类型的值

    • 				int i1 = 2;
              int i2 = 2;
              double d1 = 2.2;
              double d2 = 2.2;
              char ch1 = 'b';
              char ch2 = 'b';
              if(i1 == i2 && d1 == d2 && ch1 == ch2 ){
              
              
                  System.out.println("flag1 = " + true);//flag1 = true
              }else{
              
              
                  System.out.println("flag1 = " + false);
              }
      

3.2 比较java基本数据类型的包装类型

  • 比较java基本数据类型的包装类型:

    • 对于基本数据类型的包装类型(Byte, Short, Character,Integer,Float, Double,Long, Boolean)

    • 属于引用数据类型,用equals()

    • 除了Float和Double之外,其他的六种都是实现了常量池的,因此对于这些数据类型而言,一般也可以直接通过==来判断是否相等。

    •     Integer int1 = new Integer(127);
          Integer int2 = new Integer(127);
          Integer int3 = new Integer(128);
          Integer int4 = new Integer(128);
          System.out.println("int1 == int2?"+ (int1 == int2));//int1 == int2?true
          System.out.println("int3 == int4?"+ (int3 == int4));//int3 == int4?false
        				System.out.println("int3.equals(int4) ?"+ (int3.equals(int3)));//int3.equals(int4) ?true
      
    • int1 == int2?true:因为127在常量池中,在给int1int2赋值的时候,指向的是同一个地址,所以变量存储的地址相等。

    • int3 == int4?false: Integer 在常量池中的存储范围为[-128,127],则128不在常量池中,在给int3int4赋值的时候,会在堆内存中分别创建两个对象来保存,所以变量存储的地址不等。

    • int3.equals(int4) ?true: Integer类的equals()方法是比较的变量存储的地址所指向的内容,见其实现方法:

    •     /**
           * Compares this object to the specified object.  The result is
           * {@code true} if and only if the argument is not
           * {@code null} and is an {@code Integer} object that
           * contains the same {@code int} value as this object.
           *
           * @param   obj   the object to compare with.
           * @return  {@code true} if the objects are the same;
           *          {@code false} otherwise.
           */
          public boolean equals(Object obj) {
              
              
              if (obj instanceof Integer) {
              
              
                  return value == ((Integer)obj).intValue();
              }
              return false;
          }
      

3.3 比较比较字符串String

  • 比较字符串String

    • ==比较的是内存地址,equals比较的是值

    •     String str1 = "happy";
          String str2 = "happy";
          System.out.println("str1 == str2? "+ (str1 == str2));//str1 == str2? true
          String objStr1 = new String("like");
          String objStr2 = new String("like");
          System.out.println("objStr1 == objStr2? "+ (objStr1 == objStr2));
          //objStr1 == objStr2? false
          System.out.println("objStr1.equals(objStr2)? "+ (objStr1.equals(objStr2)));
          //objStr1.equals(objStr2)? true
      
    • str1 == str2? true:String str2 = "happy"的实现过程中,指向的是和str1相同的对象。即str1str2c存储是同一个地址,所以用==判断的结果是true.

    • objStr1 == objStr2? false:String objStr2 = new String("like")的实现过程中,会生成新的对象。即str1str2c存储是不同的地址,所以用==判断的结果是false.

    • objStr1.equals(objStr2)? true:比较的是变量存储地址所指向的内容,所以用equals()判断的结果是true

          /**
           * Compares this string to the specified object.  The result is {@code
           * true} if and only if the argument is not {@code null} and is a {@code
           * String} object that represents the same sequence of characters as this
           * object.
           *
           * @param  anObject
           *         The object to compare this {@code String} against
           *
           * @return  {@code true} if the given object represents a {@code String}
           *          equivalent to this string, {@code false} otherwise
           *
           * @see  #compareTo(String)
           * @see  #equalsIgnoreCase(String)
           */
          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;
          }
      
  • java中String 和 new String()的区别:

    • String str1 = "happy"的实现过程:首先栈区创建str引用,然后在String池(独立于栈和堆而存在,存储不可变量)中寻找其指向的内容为"happy"的对象,如果String池中没有,则创建一个,然后str指向String池中的对象,如果有,则直接指向;后来定义了字符串变量 str2 = “happy”,则直接将str2引用指向String池中已经存在的“happy”,不再重新创建对象。
      • 当str1进行了赋值(str1=“happ”),则str1将不再指向"happy",而是重新指String池中的"happ",此时如果定义String str3 = “happ”,进行str1 == str3操作,返回值为true,因为他们的值一样,地址一样,但是如果内容为"happ"的str1进行了字符串的+连接str1 = str1+“y”;此时str1指向的是在堆中新建的内容为"happy"的对象,即此时进行str1==str2,返回值false,因为地址不一样。
    • String str3 = new String(“abcd”)的实现过程:直接在堆中创建对象。如果后来又有String str4 = new String(“abcd”),str4不会指向之前的对象,而是重新创建一个对象并指向它,所以如果此时进行str3==str4返回值是false,因为两个对象的地址不一样,如果是str3.equals(str4),返回true,因为内容相同。

3.4 比较一般对象

  • 比较一般对象:

    • ==比较的是内存地址,equals()比较的也是地址

    • 一般对象没有重写equals()方法,默认调用对象Objectequals()

          /**
           * Indicates whether some other object is "equal to" this one.
           * <p>
           * The {@code equals} method implements an equivalence relation
           * on non-null object references:
           * <ul>
           * <li>It is <i>reflexive</i>: for any non-null reference value
           *     {@code x}, {@code x.equals(x)} should return
           *     {@code true}.
           * <li>It is <i>symmetric</i>: for any non-null reference values
           *     {@code x} and {@code y}, {@code x.equals(y)}
           *     should return {@code true} if and only if
           *     {@code y.equals(x)} returns {@code true}.
           * <li>It is <i>transitive</i>: for any non-null reference values
           *     {@code x}, {@code y}, and {@code z}, if
           *     {@code x.equals(y)} returns {@code true} and
           *     {@code y.equals(z)} returns {@code true}, then
           *     {@code x.equals(z)} should return {@code true}.
           * <li>It is <i>consistent</i>: for any non-null reference values
           *     {@code x} and {@code y}, multiple invocations of
           *     {@code x.equals(y)} consistently return {@code true}
           *     or consistently return {@code false}, provided no
           *     information used in {@code equals} comparisons on the
           *     objects is modified.
           * <li>For any non-null reference value {@code x},
           *     {@code x.equals(null)} should return {@code false}.
           * </ul>
           * <p>
           * The {@code equals} method for class {@code Object} implements
           * the most discriminating possible equivalence relation on objects;
           * that is, for any non-null reference values {@code x} and
           * {@code y}, this method returns {@code true} if and only
           * if {@code x} and {@code y} refer to the same object
           * ({@code x == y} has the value {@code true}).
           * <p>
           * Note that it is generally necessary to override the {@code hashCode}
           * method whenever this method is overridden, so as to maintain the
           * general contract for the {@code hashCode} method, which states
           * that equal objects must have equal hash codes.
           *
           * @param   obj   the reference object with which to compare.
           * @return  {@code true} if this object is the same as the obj
           *          argument; {@code false} otherwise.
           * @see     #hashCode()
           * @see     java.util.HashMap
           */
          public boolean equals(Object obj) {
              
              
              return (this == obj);
          }
      
      • Object类是所有类的直接或间接父类,也就是说所有的类中的equals()方法都继承自Object类,而通过上面的源可发现,Object类中equals()方法底层依赖的是==号,那么,在所有没有重写equals()方法的类中,调用equals()方法其实和使用==号的效果一样,也是比较的地址值,然而,Java提供的所有类中,绝大多数类都重写了equals()方法,重写后的equals()方法一般都是比较两个对象的值。例如前面提到的StringInteger

参考:

1.Java中==号与equals()方法的区别

2.Java 基本数据类型 及 == 与 equals 方法的区别

3.java中的基本数据类型一定存储在栈中吗?

猜你喜欢

转载自blog.csdn.net/szw_yx/article/details/106970727