今天我们将讨论一个非常重要和有趣的话题,即比较对象与对象(比较字符串和等于)。那么在Java中,对象A究竟什么时候等于对象B呢?让我们尝试写一个例子:控制台输出:假等待,停止。为什么这两辆车不相等?我们为它们分配了相同的属性,但比较的结果是假的。答案很简单。该运算符比较对象引用,而不是对象属性。两个对象甚至可能有 500 个具有相同值的字段,但比较它们仍然会产生 false。
==汽车1和汽车2指向两个不同的对象,即指向两个不同的地址。想象一下,你正在比较人们的情况。当然,在世界的某个地方,有一个人和你有同样的名字,眼睛的颜色,年龄,身高,头发颜色等。这让你们在很多方面都很相似,但你们仍然不是双胞胎——你们显然不是同一个人。
当我们使用它来比较两个对象时,运算符使用大致相同的逻辑。但是,如果您需要程序使用不同的逻辑,该怎么办?例如,假设您的程序执行 DNA 分析。它比较了两个人的遗传密码,并确定他们是否是双胞胎。 控制台输出:false 我们得到相同的逻辑结果(因为我们没有太大变化),但现在这个逻辑不好!毕竟,在现实生活中,DNA分析应该给我们100%的保证,我们有双胞胎站在我们面前。但是我们的程序和操作员告诉我们相反的情况。我们如何改变这种行为,并确保程序在DNA匹配时输出正确的结果?Java对此有一种特殊的方法:==
==等于().喜欢到字符串()方法,我们之前讨论过,等于()属于对象class — Java 中最重要的类,所有其他类派生自的类。但等于()不会自行更改程序的行为: 控制台输出: false 完全相同的结果,那么我们需要此方法做什么呢?:/一切都很简单。这里的问题是,我们目前正在使用此方法,因为它是在
对象类。如果我们进入代码对象类并查看方法的实现,这就是我们将看到的:这就是程序行为没有改变的原因!完全相同的运算符(用于比较引用)在
==等于()方法对象类。但是这种方法的诀窍在于我们可以覆盖它。覆盖方式编写自己的等于()我们的方法男人类,给它我们需要的行为!目前,我们不喜欢这样一个事实:人1.等于(人2)本质上等效于人1 == 人2.以下是我们在这种情况下将执行的操作: 控制台输出:true 现在我们得到了一个完全不同的结果!通过编写我们自己的
等于()方法并使用它而不是标准方法,我们已经产生了正确的行为:现在,如果两个人具有相同的DNA,程序报告“DNA分析已证明他们是双胞胎”并返回真实!通过覆盖等于()方法在你的类中,你可以很容易地创建任何你需要的对象比较逻辑。事实上,我们刚刚谈到了对象比较。在我们面前,关于这个主题仍然有一个很大的独立课程(如果你有兴趣,你现在浏览一下)。
在 Java 中比较字符串
为什么我们要将字符串比较与其他所有内容分开考虑?现实情况是,字符串本身就是编程中的一个主题。首先,如果你把所有曾经编写的Java程序都拿来,你会发现其中大约25%的对象是字符串。所以这个话题非常重要。其次,比较字符串的过程确实与其他对象非常不同。考虑一个简单的例子:控制台输出:false 但是为什么我们得到假呢?毕竟,字符串完全相同,逐字逐句:/您可能已经猜到了原因:
这是因为运算符比较引用==!清楚s1和s2内存中具有不同的地址。如果你想到这一点,那么让我们重新制作我们的例子:现在我们又有两个引用,但结果恰恰相反:控制台输出:真的无助地困惑?让我们弄清楚发生了什么。操作员确实比较了内存地址。这总是正确的,你不需要怀疑它。这意味着如果
==s1 == s2返回 true,则这两个字符串具有相同的地址。这是真的!现在是时候向您介绍用于存储字符串的特殊内存区域:字符串池
字符串池是用于存储您在程序中创建的所有字符串值的区域。为什么创建它?如前所述,字符串表示所有对象的巨大百分比。任何大型程序都会创建大量字符串。创建字符串池是为了节省内存:字符串被放置在那里,然后创建的字符串引用相同的内存区域 - 无需每次都分配额外的内存。每次你写字符串 = “.....”程序检查字符串池中是否有相同的字符串。如果有,则不会创建新字符串。新的引用将指向字符串池中的相同地址(相同字符串所在的地址)。所以当我们写
s2指向 与 相同的位置s1.第一条语句在字符串池中创建新字符串。第二个语句仅引用与s1.您可以再制作500个相同的字符串,结果不会改变。等一会。如果这是真的,那么为什么这个例子以前不起作用呢? 我认为你的直觉已经告诉你原因=)在进一步阅读之前尝试猜测。您可以看到这两个字符串以不同的方式声明。一个带有新操作员,另一个没有新操作员。原因就在这里。当
新增功能运算符用于创建对象,它强制为对象分配新的内存区域。以及使用新增功能不会最终出现在字符串池中 — 它成为一个单独的对象,即使它的文本与字符串池中的字符串完全匹配。也就是说,如果我们编写以下代码:在内存中,它看起来像这样:
每次使用创建新对象时新增功能,则分配一个新的内存区域,即使新字符串内的文本是相同的!看来我们已经找到了操作员。但是我们的新认识呢,==等于()方法? 控制台输出:真正有趣。我们确信
s1和s2指向内存中的不同区域。但是等于()方法仍然告诉我们它们是相等的。为什么?请记住,我们之前说过等于()方法可以被覆盖以比较我们想要的对象?这就是他们所做的字符串类。它覆盖等于()方法。它不是比较引用,而是比较字符串中的字符序列。如果文本相同,则它们是如何创建的或存储在何处并不重要:无论是在字符串池中还是在单独的内存区域中。比较的结果将为真。顺便说一句,Java允许您执行不区分大小写的字符串比较。通常,如果其中一个字符串具有全部大写字母,则比较的结果将为 false:控制台输出:false 对于不区分大小写的比较,
字符串类具有等于虚无案例()方法。如果您只关心比较特定字符的顺序而不是字母大小写,则可以使用它。例如,这在比较两个地址时可能会有所帮助:在这种情况下,我们显然是在谈论相同的地址,因此使用
等于虚无案例()方法。
字符串.实习生() 方法
这字符串类还有一个棘手的方法:实习生();这实习生()方法直接与字符串池一起工作。如果您拨打实习生()方法在一些字符串上:
它检查字符串池中是否有匹配的字符串
如果有,它将返回对池中字符串的引用
如果不是,它将字符串添加到字符串池并返回对它的引用。
使用后实习生()字符串引用上的方法,该方法使用新增功能,我们可以使用运算符将其与字符串池中的字符串引用进行比较。 控制台输出:true 当我们之前比较这些字符串时,没有==
实习生(),结果是错误的。现在实习生()方法检查字符串“CodeGym是学习Java的最佳站点!”是否在字符串池中。当然,它是:我们创建它与我们检查
String s1 = "CodeGym is the best website for learning Java!";
s1和返回的引用s2.实习生()指向内存的同一区域。当然,他们确实:)总之,记住并应用这个重要的规则:始终使用等于()比较字符串的方法!在比较字符串时,我们几乎总是想比较它们的字符,而不是引用,内存区域或其他任何东西。这等于()方法完全符合您的需要。