JavaRush /Java 博客 /Random-ZH /Java 中的等于和字符串比较 - 字符串比较

Java 中的等于和字符串比较 - 字符串比较

已在 Random-ZH 群组中发布
你好!今天我们要讲一个非常重要且有趣的话题,即Java中对象之间的比较equals() 。事实上,在 Java 中什么情况下对象A等于对象B等于和字符串比较 - 1让我们尝试写一个例子:
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
控制台输出:

false
好吧,停下来。事实上,为什么这两辆车不相等?我们给了它们相同的属性,但比较的结果是错误的。答案很简单。该运算符==比较的不是对象的属性,而是链接。即使两个对象有 500 个相同的属性,比较的结果仍然是 false。毕竟,链接car1指向car2 两个不同的对象、两个不同的地址。想象一下比较人的情况。世界上很可能有一个人和你有相同的名字、眼睛颜色、年龄、身高、头发颜色等。也就是说,你们在很多方面都很相似,但仍然不是双胞胎,尤其不是同一个人。 当我们使用它来比较两个对象时,等于和字符串比较 - 2该运算符应用大致相同的逻辑。==但是如果您的程序需要不同的逻辑怎么办?例如,如果您的程序模拟 DNA 分析。她必须比较两个人的 DNA 代码并确定他们是双胞胎。
public class Man {

   int dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1 == man2);
   }
}
控制台输出:

false
按逻辑,结果是一样的(毕竟我们没有改变任何东西),但现在我们对此不满意!确实,在现实生活中,DNA分析百分百保证我们面对的是双胞胎。但我们的程序和操作员==告诉我们事实并非如此。我们怎样才能改变这种行为并确保如果 DNA 测试匹配,程序就会产生正确的结果?为此,Java 中创建了一个特殊的方法 - equals()

Java 中的 equals() 方法

与我们前面讨论的方法一样toString()equals()属于类,ObjectJava 中最重要的类,所有其他类都派生于该类。然而,equals() 本身不会以任何方式改变我们程序的行为:
public class Man {

   String dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = "111122223333";

       Man man2 = new Man();
       man2.dnaCode = "111122223333";

       System.out.println(man1.equals(man2));
   }
}
控制台输出:

false
结果完全一样,那么为什么需要这个方法呢?:/ 这很简单。事实上,现在我们使用了这个方法,因为它是在类本身中实现的Object。如果我们进入类代码Object并查看该方法是如何在其中实现以及它的作用,我们将看到:
public boolean equals(Object obj) {
   return (this == obj);
}
这就是我们程序的行为没有改变的原因!在类的 equals() 方法中Object存在相同的引用比较==. 但这个方法的技巧是我们可以重写它。覆盖意味着在我们的类中编写您自己的 equals() 方法Man并使其按照我们想要的方式运行!现在我们不满意该检查man1.equals(man2)本质上与 执行相同的操作man1 == man2。在这种情况下我们会这样做:
public class Man {

   int dnaCode;

   public boolean equals(Man man) {
       return this.dnaCode ==  man.dnaCode;
   }

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1.equals(man2));

   }
}
控制台输出:

true
完全不同的结果!通过编写我们自己的 equals() 方法而不是标准方法,我们实现了正确的行为:现在如果两个人具有相同的 DNA 代码,程序会告诉我们:“DNA 分析表明他们是双胞胎”并返回 true!通过重写类中的 equals() 方法,您可以轻松创建必要的对象比较逻辑。我们只是笼统地谈到了物体的比较。我们接下来还会有一个关于这个主题的 单独的大型讲座(如果您感兴趣,您现在可以快速阅读)。

Java 中的字符串比较 - 字符串比较

为什么我们将字符串比较与其他所有内容分开处理?嗯,事实上,编程中的台词是一个完全不同的故事。首先,如果你拿人类编写的所有Java程序来说,其中大约25%的对象是由它们组成的。因此,这个话题非常重要。其次,比较字符串的过程确实与其他对象有很大不同。让我们看一个简单的例子:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2);
   }
}
控制台输出:

false
但为什么是假的呢?这些行是完全相同的,逐字逐句:/您可以假设:这是因为运算符 == 比较引用!毕竟,s1它们s2在内存中具有不同的地址。如果你有这个想法,那么让我们重做我们的例子:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = "JavaRush is the best site to learn Java!";
       System.out.println(s1 == s2);
   }
}
现在我们也有两个链接,但结果却变成了相反: 控制台输出:

true
完全困惑吗?:) 让我们弄清楚吧。该运算符==实际上比较内存中的地址。这个规则总是有效的,没有必要怀疑它。这意味着如果s1 == s2返回 true,则这两个字符串在内存中具有相同的地址。确实如此!现在是时候熟悉一个用于存储字符串的特殊内存区域了 - 字符串池 ( String pool) 等于和字符串比较 - 3字符串池是一个用于存储您在程序中创建的所有字符串值的区域。它是为了什么而创建的?正如前面提到的,字符串占据了所有对象的很大一部分。在任何大型程序中,都会创建很多行。为了节省内存,这就是所需要的String Pool- 一行您需要的文本放置在那里,以后新创建的链接引用相同的内存区域,无需每次分配额外的内存。每次写入时String = “........”,程序都会检查字符串池中是否存在包含此类文本的行。如果有,则不会创建新的。并且新的链接将指向字符串池中存储该字符串的相同地址。因此,当我们在程序中写入
String s1 = "JavaRush is the best site to learn Java!";
String s2 = "JavaRush is the best site to learn Java!";
该链接s2指向与 完全相同的位置s1。第一个命令在字符串池中创建了一个新行,其中包含我们需要的文本,而当执行第二个命令时,它只是引用与 相同的内存区域s1。您可以用相同的文本再制作至少 500 行,结果不会改变。停止。但为什么这个例子之前对我们不起作用呢?
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2);
   }
}
我认为,凭直觉,您已经猜到原因是什么了:) 在进一步阅读之前尝试猜测。您可以看到这两行的创建方式不同。一是有操作员的帮助new,二是没有操作员的帮助。正是这个原因。new运算符在创建对象时,会强制为其在内存中分配一块新的区域。并且用 , 创建的行new不会以 结尾String Pool:它成为一个单独的对象,即使它的文本与 'a. 中的同一行完全相同String Pool。也就是说,如果我们编写以下代码:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = "JavaRush is the best site to learn Java!";
       String s3 = new String("JavaRush is the best site to learn Java!");
   }
}
在内存中它看起来像这样: 等于和字符串比较 - 4每次创建一个新对象时,new都会在内存中分配一个新区域,即使新行内的文本是相同的!我们似乎已经解决了运算符==,但是我们的新朋友 - equals() 方法呢?
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1.equals(s2));
   }
}
控制台输出:

true
有趣的。我们确切地知道什么s1s2指向内存中的不同区域。但是,尽管如此,equals() 方法表明它们是相等的。为什么?还记得吗,上面我们说过可以在类中重写 equals() 方法,以便它按照您需要的方式比较对象?这就是他们在课堂上所做的String。它有一个重写的 equals() 方法。它比较的不是链接,而是字符串中的字符序列。如果字符串中的文本相同,那么它们的创建方式和存储位置并不重要:在字符串池中,还是在单独的内存区域中。比较的结果将是真实的。顺便说一下,Java 允许您以不区分大小写的方式正确比较字符串。正常情况下,如果你写其中一行,例如大写,比较的结果将为 false:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JAVARUSH - ЛУЧШИЙ САЙТ ДЛЯ ИЗУЧЕНИЯ JAVA!");
       System.out.println(s1.equals(s2));
   }
}
控制台输出:

false
对于这种情况,该类String有一个方法equalsIgnoreCase()。如果比较的主要内容是特定字符的序列,而不是大小写,则可以使用它。例如,这在比较两个电子邮件地址时非常有用:
public class Main {

   public static void main(String[] args) {

       String address1 = "Moscow, Academician Korolev street, 12";
       String address2 = new String("Г. МОСКВА, УЛ. АКАДЕМИКА КОРОЛЕВА, ДОМ 12");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
在这种情况下,很明显我们正在谈论相同的地址,因此使用该方法equalsIgnoreCase()将是正确的决定。

String.intern() 方法

该类String还有另一个棘手的方法 - intern(); 该方法intern()直接与String Pool'om. intern()如果您在字符串上 调用方法,它会:
  • 查看字符串池中是否存在带有此文本的字符串
  • 如果存在,则返回池中指向它的链接
  • 如果没有,它会在字符串池中放置一行包含此文本的行,并返回指向该文本的链接。
通过将该方法应用于intern()通过 new 创建的字符串引用,我们可以将其与通过String Pool'a 的字符串引用进行比较==
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2.intern());
   }
}
控制台输出:

true
以前,当我们在没有 的情况下比较它们时intern(),结果是错误的。现在,该方法intern()检查是否存在包含文本“JavaRush - 学习 Java 的最佳网站!”的行。在字符串池中。当然它就在那里:我们在编写时创建了它
String s1 = "JavaRush is the best site to learn Java!";
经过检查,引用s1和方法返回的引用s2.intern()是否指向内存中的同一区域,当然,它们确实如此:) 总结一下,记住并使用主要规则:要比较字符串,始终使用 equals()方法!比较字符串时,几乎总是指比较它们的文本,而不是引用、内存区域等。equals() 方法正是您所需要的。以下是一些链接供大家自行学习:
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION