equals( )方法与 == 运算符的用法比较

时间:2022-03-16 16:15:34
 

某些读者们肯定会对何时使用等于运算符"=="以及何时使用equals()方法类感到困惑,这种惑主要是equals(...)方法和"=="运算符的混淆.尽管它们有时产生的结果一样,然而实际上,它们的用法是不同的。看看下面的例子: 
 
public class StringExample
{
     public static void main (String args[])
     {
         String s0 = "Programming";
         String s1 = new String ("Programming");
         String s2 = "Program" + "ming";
 
         System.out.println("s0.equals(s1): " + (s0.equals(s1)));
         System.out.println("s0.equals(s2): " + (s0.equals(s2)));
         System.out.println("s0 == s1: " + (s0 == s1));
         System.out.println("s0 == s2: " + (s0 == s2));
     }
}
 
  这个例子包含了3个String型变量,其中两个被赋值以常量表达式“Programming”另一个被赋值以一个新建的值为“Programming”的String 类的实例,使用equals(...)方法和“==”运
算符进行比较,产生了下列结果: 
 
s0.equals(s1): true
s0.equals(s2): true
s0 == s1: false
s0 == s2: true

   String.equals()方法比较的是字符串的内容,使用equals(...)方法会对字符串中的所有字符一个接一个地进行比较,如果完全相等,那么返回true。在这种情况下,全部个字符串都是相同的,所以当字符串s0与s1或s2比较时,我们得到的返回值均为 true。运算符“==”比较的是 String实例的引用,在这种情况下很明显s0和s1并不是同一个String实例。但s0和s2却是同一个。也许你会问s0和s2怎么是同一个对象呢?这个问题的答案来自于Java 语言规范中关于字符串常量String Literals的章节。本例中“Programming”,“Program”和“ming”都是字符串常量。它们在编译期就被确定了,当一个字符串由多个字符串常量连接而成时,例如s2它同样在编译期就被确定为一个字符串常量。Java确保一个字符串常量只有一份拷贝,所以当“Programming”和“Program”+“ming”被确定为值相等时,Java 会设置两个变量的引用为同一个常量的引用,在常量池constant pool中Java会跟踪所有的字符串常量 。
   常量池指的是在编译期被确定 并被保存在已编译的.class 文件中的一些数据,它包含了关于方法、类、接口等等,当然还有字符串常量的信息。当 JVM 装载了这个.class 文件,变量 s0 和s2被确定。JVM执行了一项名为常量池解析constant pool resolution 的操作,该项操作针对字符串的处理过程,包括下列 3 个步骤(摘自 JVM 规范 5.4节): 
--- 如果另一个常量池入口constant pool entry 被标记为 CONSTANT_String,并且指出        样的Unicode字符序列已经被确定,那么这项操作的结果就是为之前的常量池入口创建         的String实例的引用。
---否则,如果 intern()方法已经被这个常量池描述的一个包含同样Unicode字符序列的
      String实例调用过了,那么这项操作的结果就是那个相同String实例的引用。
---否则,一个新的String 实例会被创建,它包含了CONSTANT_String入口描述的Unicode字      符序列,这个String实例就是该项操作的结果。
   也就是说,当常量池第一次确定一个字符串,在Java内存栈中就创建一个String 实例。在常量池中,后来的所有针对同样字符串内容的引用,都会得到之前创建的String实例,当JVM 处理到第6行时,它创建了字符串常量 Programming的一份拷贝到另一个String 实例中,所以 对s0 和s1 的引用的比较结果是false。因为它们不是同一个对象,这就是为何s0==s1 的操作在某些情况下与 s0.equals(s1)不同,s0==s1 比较的是对象引用的值,而s0.equals(s1)实际上执行的是字符串内容的比较。
  因而我们要测试两个对象所指的值是否相等时,我们应该使用equals()方法,其基准点是属性(attributes)。 操作符"=="只是"浅层地"测试相等性,看看操作符左侧的东西是不是和右边的一样,因而用于测试两个基本型别是否完全相同(identical),或测试两个object references是否指向同一个对象。