Comment remplacer correctement la méthode égale en Java
1. Quelle est la méthode égale ?
Il faut d'abord savoir que la Classe Objet
est la classe parent (super classe/classe de base) de toutes les classes en Java
, c'est-à-dire en Java
Dans le code>, toutes les classes héritent de la Classe Objet
par défaut. Autrement dit, nous pouvons utiliser directement toutes les méthodes implémentées dans la Classe Objet
. La méthode equals
est l'une des nombreuses méthodes implémentées par la Classe Object
. Object类
是 Java
中所有类的父类(超类/基类),也就是说,在Java
中,所有的类都是默认继承自Object类
的,换言之,Object类
中所实现的方法我们都可以直接拿来用。而equals
方法便是Object类
所实现的众多方法之一。
以下截图自Java11 API
Object类的所有方法:
1.1 equals方法:
equals
:是Object类
中的方法,只能判断引用类型,等下可以带大伙看看jdk
源码默认判断的是地址是否相等(因为引用类型变量底层本质就是来存储对象地址的,有C/C++知识的小伙伴应该很了解 ),在子类中往往会重写该方法,用于判断对象的内容是否相等。比如等下会简单了解到的
Integer
和String
(在IDEA里看源码实现 )
2. 为什么要重写equals方法?
我们有Object类
实现的equals
方法能用不就行了?为啥还得重写equals
方法呢?这就要看看Object类
的equals
方法实现机制了。
我们可以清楚地看到,Object类
的equals
方法底层是用 == 来实现的,也就是说它的用法跟我们平常用来比较基本数据类型的 == 用法一致。我们首先来看一下 == 的语法:
== 只能用来比较基本数据类型是否相等,也就是单纯的值比较;
== 在比较浮点数的时候也可能存在失效的情况,这是因为浮点数的存储机制跟整型家族不一样,浮点数本身就不能表示一个精确的值(具体原因可自行查看IEEE 754规则,这里不再展开)
所以我们在单纯的进行基本数据类型的值比较时可以用 == ,而比较引用数据类型就不能这么做,前面有提到,引用数据类型本质上是来引用/存储对象的地址的,所有你完全可以把它当做C/C++
的指针来看待(这里杠一句说Java没有指针的,个人觉得只是叫法不同罢了 )
注: 不要把Java
引用跟C++
引用搞混了,C++引用其实是指针常量,即int* const
,这也是C++
的引用只能作为一个变量的别名的原因。
2.1 举个例子吧~
比较两个int时可以直接用 == ,当它们相等时结果为true
,而当new
了两个属性完全一样的对象时,再用 ==
来进行比较就会出现错误,如我们所见,明明我们应该想要得到true
的,结果却是false
源码:
运行结果:
到这里,我们应该大致清楚为啥要在比较对象时重写equals
方法了,因为Object类
提供给我们的不好使~~
3. 分析equals源码:
在进行重写之前,我们依旧来看看Java API
中的定义:public boolean equals(Object obj)
作用:指示某个其他对象是否“等于”此对象。
equals方法在非null对象引用上实现等价关系:
自反性 :对于任何非空的参考值
x
,x.equals(x)
应该返回true
。对称性 :对于任何非空引用值
x
和y
,x.equals(y)
应该返回true
当且仅当y.equals(x)
回报true
。-
传递性 :对于任何非空引用值
Les captures d'écran suivantes sont tirées de l'x
,y
和z
,如果x.equals(y)
回报true
个y.equals(z)
回报true
,然后x.equals(z)
应该返回true
API Java11
🎜🎜🎜🎜Toutes les méthodes de la classe Object : 🎜🎜
🎜
Méthode égale 1.1 :
- 🎜
equals : Oui La méthode dans la <code>Object class
ne peut déterminer que le type de référence. Je pourrai vous montrer le code source dujdk
plus tard🎜 - 🎜By. par défaut, elle détermine si l'adresse est Égalité (car l'essence sous-jacente des variables de type référence est de stocker des adresses d'objet, que les amis ayant des connaissances en C/C++ devraient très bien connaître), cette méthode est souvent remplacée dans les sous-classes pour déterminer si le contenu de les objets sont égaux. Par exemple,
Integer
etString
, que vous découvrirez plus tard (voir l'implémentation du code source dans IDEA)🎜
equals
implémentée par laObject class
? Pourquoi devons-nous remplacer la méthodeequals
? Cela dépend du mécanisme d'implémentation de la méthodeequals
de laClasse Object
. 🎜🎜🎜🎜Nous pouvons comprendre On peut voir clairement que la méthode
equals
de laClasse Object
est implémentée en utilisant == en bas, ce qui signifie que son utilisation est la même que celle == que nous avons habituellement utiliser pour comparer les types de données de base. L'utilisation est cohérente. Jetons d'abord un coup d'œil à la syntaxe de == : 🎜- 🎜== ne peut être utilisé que pour comparer les types de données de base pour l'égalité, ce qui est une simple comparaison de valeurs ; 🎜 li>
- 🎜== Il peut également y avoir des échecs lors de la comparaison des nombres à virgule flottante. En effet, le mécanisme de stockage des nombres à virgule flottante est différent de celui de la famille entière. Le nombre à virgule flottante lui-même ne peut pas représenter un nombre précis. valeur (la raison spécifique peut être Vérifiez les règles IEEE 754 par vous-même, pas plus de détails ici) 🎜
C/C++ code> (ici il est dit que Java n'a pas de pointeurs, personnellement je pense que c'est juste un nom différent)<br>Remarque : Ne confondez pas la référence <code>Java
avec leC++ référence. La référence C++ est en fait une constante de pointeur, c'est-à-dire <code> int* const
, c'est pourquoi la référence deC++
ne peut être utilisée que comme alias de. une variable. 🎜2.1 Donnons un exemple~
🎜Lorsque vous comparez deux entiers, vous pouvez directement utiliser == Lorsqu'ils sont égaux, le résultat esttrue
, et lorsquenew.
Lorsque deux objets avec exactement les mêmes attributs sont comparés, une erreur se produira si==
est utilisé pour la comparaison. Comme nous pouvons le voir, nous devrions évidemment vouloir obtenirtrue<.> , le résultat est <code>false
Code source : 🎜🎜🎜🎜Résultats d'exécution : 🎜🎜
🎜🎜À ce stade, nous devrions avoir une idée générale de la raison pour laquelle nous devons remplacer la méthode
equals
lorsque comparer des objets, car laClasse Objet
Le code> qui nous est fourni ne fonctionne pas~~🎜🎜3 Analysez le code source égal : 🎜🎜Avant de réécrire, jetons quand même un œil à la définition dans.API Java
:
public boolean equals(Object obj)
Fonction : Indique si un autre objet est "égal" à cet objet. 🎜🎜La méthode equals implémente l'équivalence sur les références d'objets non nulles : 🎜- 🎜Réflexivité : pour toute valeur de référence non nulle
x
,x.equals(x)
devrait renvoyertrue
. 🎜 - 🎜Symétrie : Pour toute valeur de référence non nulle
x
ety
,x.equals(y)
Should Renvoietrue
si et seulement siy.equals(x)
renvoietrue
. 🎜 - 🎜Transitivité : pour toute valeur de référence non nulle
x
,y
etz
, six .equals(y)
renvoietrue
y.equals(z)
renvoietrue
, puisx.equals ( z)
doit renvoyertrue
. 🎜 Cohérence : appels multiples à
x.equals(y pour toute valeur de référence non nulle <code>x
ety
) renvoie toujourstrue
ou renvoie toujoursfalse
si les informations utilisées dans la comparaisonequals
sur l'objet n'ont pas été modifiées.x
和y
,多次调用x.equals(y)
始终返回true
或始终返回false
,前提是未修改对象上的equals
比较中使用的信息。对于任何非空的参考值
x
,x.equals(null)
应该返回false
。
类Object的equals方法实现了对象上最具区别的可能等价关系; 也就是说,对于任何非空引用值x和y ,当且仅当x和y引用同一对象( x == y具有值true )时,此方法返回true 。
注意:通常需要在重写此方法时覆盖hashCode方法,以便维护
hashCode
方法的常规协定,该方法声明相等对象必须具有相等的哈希代码。接下来看看
String类
中重写的equals
方法和Integer
类中重写的equals
方法://String类equals源代码: 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; }
Copier après la connexion简单解读一下就是当对比的是同一个对象时,直接返回
true
,提高效率。当传进来的对象是当前类的实例时,进入进一步的判断,一个for
循环依次遍历字符串每一个字符,只要有一个字符不同就返回false
。继续来看看
Integer
类的equals
源代码://Integer类的equals源代码: public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
Copier après la connexionInteger类
的equals
源码简单许多,只要传入的对象是当前类的实例,就进行进一步的判断:当它们的值相等时,就返回true
,不相等就返回false
。这里还是来实际演示一下⑧,就以
Integer类
为例:很明显,我们知道
Integer类
重写了equals
方法且是引用类型。当直接用 == 来比较引用类型变量时,结果是false
,而用equals
判断结果为true
。这便很好地说明了重写equals
方法的必要性。String类
大伙自己验证一哈⑧。4. 正确重写equals方法:
(先说结论,
getClass()
比instanceof
更安全)到这里,我们基本把
equals
方法的各种源码都分析了一遍,接下来就是我们自己要来实现equals
方法了。这里提供两个比较常见的
equals
重写方法:用
instanceof
实现重写equals
方法用
getClass
实现重写equals
方法
假设有此场景:
在已经创建好的长方形类中重写
Objec
t类中的equals
方法为当长方形的长和宽相等时,返回TRUE
,同时重写hashCode
方法,重写toString
方法为显示长方形的长宽信息。并测试类。package com.test10_04; import java.util.Objects; class Rectangle { private double length; private double wide; public Rectangle() { //空实现 } public Rectangle(double length, double wide) { setLength(length); setWide(wide); } public double getLength() { return length; } public void setLength(double length) { assert length > 0.0 : "您的输入有误,长方形的长不能小于0"; this.length = length; } public double getWide() { return wide; } public void setWide(double wide) { assert wide > 0.0 : "您的输入有误,长方形的宽不能小于0"; this.wide = wide; } public double area() { return this.length * this.wide; } public double circumference() { return 2 * (this.wide + this.length); } public boolean equals(Object obj) { if (this == obj) { //判断一下如果是同一个对象直接返回true,提高效率 return true; } if (obj == null || obj.getClass() != this.getClass()) { //如果传进来的对象为null或者二者为不同类,直接返回false return false; } //也可以以下方法: // if (obj == null || !(obj instanceof Rectangle)) { //如果传进来的对象为null或者二者为不同类,直接返回false // return false; // } Rectangle rectangle = (Rectangle) obj; //向下转型 //比较长宽是否相等,注意:浮点数的比较不能简单地用==,会有精度的误差,用Math.abs或者Double.compare return Double.compare(rectangle.length, length) == 0 && Double.compare(rectangle.wide, wide) == 0; } public int hashCode() { //重写equals的同时也要重写hashCode,因为同一对象的hashCode永远相等 return Objects.hash(length, wide); //调用Objects类,这是Object类的子类 } public String toString() { return "Rectangle{" + "length=" + length + ", wide=" + wide + '}'; } } public class TestDemo { public static void main(String[] args) { Rectangle rectangle1 = new Rectangle(3.0, 2.0); Rectangle rectangle2 = new Rectangle(3.0, 2.0); System.out.println(rectangle1.equals(rectangle2)); System.out.println("rectangle1哈希码:" + rectangle1.hashCode() + "\nrectangle2哈希码:" + rectangle2.hashCode()); System.out.println("toString打印信息:" + rectangle1.toString()); } }
Copier après la connexion具体实现思路在代码中讲的很清楚了,我们这里重点分析一下
getClass
和instanceof
两种实现方法的优缺点:将代码逻辑简化一下:
我们就重点看这段简单的代码//getClass()版本 public class Student { private String name; public void setName(String name) { this.name = name; } @Override public boolean equals(Object object){ if (object == this) return true; // 使用getClass()判断对象是否属于该类 if (object == null || object.getClass() != getClass()) return false; Student student = (Student)object; return name != null && name.equals(student.name); }
Copier après la connexion//instanceof版本 public class Student { private String name; public void setName(String name) { this.name = name; } @Override public boolean equals(Object object){ if (object == this) return true; // 通过instanceof来判断对象是否属于类 if (object == null || !(object instanceof Student)) return false; Student student = (Student)object; return name!=null && name.equals(student.name); } }
Copier après la connexion事实上两种方案都是有效的,区别就是
getClass()
限制了对象只能是同一个类,而instanceof
却允许对象是同一个类或其子类,这样equals方法就变成了父类与子类也可进行equals操作了,这时候如果子类重定义了equals方法,那么就可能变成父类对象equlas子类对象为true,但是子类对象equlas父类对象就为false了,如下所示:class GoodStudent extends Student { @Override public boolean equals(Object object) { return false; } public static void main(String[] args) { GoodStudent son = new GoodStudent(); Student father = new Student(); son.setName("test"); father.setName("test"); // 当使用instance of时 System.out.println(son.equals(father)); // 这里为false System.out.println(father.equals(son)); // 这里为true // 当使用getClass()时 System.out.println(son.equals(father)); // 这里为false System.out.println(father.equals(son)); // 这里为false } }
Copier après la connexion注意看这里用的是
getClass()
返回值两个都是
false
,符合我们的预期,(连类都不一样那肯定得为false
啊)而换成
instanceof
#🎜🎜#Pour toute valeur de référence non nulle
x
,x.equals(null)
devrait renvoyerfaux
. - 🎜
hashCode
, qui stipule que les objets égaux doivent avoir des valeurs égales. codes de hachage. #🎜🎜##🎜🎜#
equals
remplacée dans la String class
et à la classe Integer
remplacée code>égal àMéthode : #🎜🎜##🎜🎜#
true
est renvoyé directement pour améliorer l'efficacité. Lorsque l'objet transmis est une instance de la classe actuelle, un jugement supplémentaire est entré. Une boucle for
parcourt tour à tour chaque caractère de la chaîne tant qu'un caractère est différent, false<.> est renvoyé. #🎜🎜##🎜🎜# Continuons à regarder le code source <code>equals
de la classe Integer
: #🎜🎜##🎜🎜#
Classe entière Le code source de <code>equals
est beaucoup plus simple. Tant que l'objet transmis est une instance de la classe actuelle, un jugement plus approfondi sera effectué : quand leurs valeurs sont sont égaux, true
sera renvoyé S'il n'est pas égal, renvoie false
. #🎜🎜##🎜🎜# Faisons une démonstration pratique⑧, en prenant comme exemple la Classe Integer
: #🎜🎜##🎜🎜#
Integer Remplace la méthode <code>equals
et est un type référence. Lorsque == est utilisé directement pour comparer des variables de type référence, le résultat est false
, et lorsque equals
est utilisé pour déterminer le résultat est true
. Cela illustre bien la nécessité de remplacer la méthode equals
. Classe de chaînes
Veuillez le vérifier vous-même⑧. #🎜🎜#4. Réécrivez correctement la méthode equals :
#🎜🎜# (Permettez-moi d'abord de parler de la conclusion,getClass()
est plus sûr que instanceof) #🎜🎜##🎜🎜#À ce stade, nous avons essentiellement analysé les différents codes sources de la méthode <code>equals
. L'étape suivante consiste à implémenter equals méthode nous-mêmes. #🎜🎜##🎜🎜#Voici deux méthodes courantes de réécriture <code>equals
: #🎜🎜#- #🎜🎜##🎜🎜 #Utilisez
instanceof
pour implémenter la réécriture de la méthode equals
#🎜🎜##🎜🎜##🎜🎜##🎜🎜#Utilisez getClass
pour implémenter la réécriture de égal
Méthode#🎜🎜##🎜🎜#Le <code>equals dans la classe >Objec
t renvoie TRUE
lorsque la longueur et la largeur du rectangle sont égales, et remplace en même temps la méthode hashCode
, remplacez la méthode toString
pour afficher les informations de longueur et de largeur du rectangle. et tester la classe. #🎜🎜#rrreee#🎜🎜#Les idées d'implémentation spécifiques sont clairement énoncées dans le code. Ici, nous nous concentrons sur l'analyse des avantages et des inconvénients des deux méthodes d'implémentation getClass
et instanceof :#🎜🎜##🎜🎜#<img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/887/227/168360237265000.jpg" class="lazy" alt="Comment réécrire correctement la méthode égale dans Java">#🎜🎜##🎜🎜#Simplifier la logique du code :<br>Concentrons-nous sur ce code simple#🎜🎜#rrreeerrreee#🎜🎜#En fait, les deux solutions sont valables, la différence est <code> getClass()
restreint l'objet à la même classe, mais instanceof
permet à l'objet d'être la même classe ou sa sous-classe, donc la méthode égale devient la classe parent L'opération égale peut également être effectué avec des sous-classes. À ce stade, si la sous-classe redéfinit la méthode égale, elle peut devenir l'objet de classe parent equlas, l'objet de sous-classe est vrai, mais l'objet de sous-classe equlas, l'objet de classe parent est faux, comme suit : #🎜🎜#rrreee #🎜🎜# Notez que getClass()
est utilisé ici #🎜🎜##🎜🎜#
false
, conformément à nos attentes, (même si les classes sont différentes, cela doit être false
) #🎜🎜##🎜🎜#
instanceof
: #🎜🎜##🎜 🎜##🎜🎜##🎜🎜#Résultats d'exécution : l'un est true
et l'autre est false
. Il est évident qu'il y a un problème. true
一个为false
,很明显出现问题了。
这里的原因如下:instanceof
的语法是这样的:
当一个对象为一个类的实例时,结果才为true
。但它还有一个特点就是,如果当这个对象时其子类的实例时,结果也会为true
。这便导致了上述的bug。也就是说当比较的两个对象,他们的类是父子关系时,instanceof
可能会出现问题。**需要深究的小伙伴可以自己去了解一哈,所以在这里建议在实现重写equals
方法时,尽量使用getClass
来实现。
在重写equals
方法的同时需要重写hashCode

instanceof
est la suivante : Lorsqu'un objet est une instance d'une classe, le résultat est
true
. Mais il a aussi la particularité que si cet objet est une instance de sa sous-classe, le résultat sera également true
. Cela conduit au bug ci-dessus. Autrement dit, lorsque les deux objets comparés ont une relation parent-enfant, instanceof
peut poser des problèmes. **Les amis qui ont besoin d'étudier davantage peuvent l'apprendre par eux-mêmes, il est donc recommandé d'essayer d'utiliser getClass
lors de la réécriture de la méthode equals
pour y parvenir. 🎜🎜Lorsque vous remplacez la méthode equals
, vous devez remplacer la méthode hashCode
. 🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.

Les capsules sont des figures géométriques tridimensionnelles, composées d'un cylindre et d'un hémisphère aux deux extrémités. Le volume de la capsule peut être calculé en ajoutant le volume du cylindre et le volume de l'hémisphère aux deux extrémités. Ce tutoriel discutera de la façon de calculer le volume d'une capsule donnée en Java en utilisant différentes méthodes. Formule de volume de capsule La formule du volume de la capsule est la suivante: Volume de capsule = volume cylindrique volume de deux hémisphères volume dans, R: Le rayon de l'hémisphère. H: La hauteur du cylindre (à l'exclusion de l'hémisphère). Exemple 1 entrer Rayon = 5 unités Hauteur = 10 unités Sortir Volume = 1570,8 unités cubes expliquer Calculer le volume à l'aide de la formule: Volume = π × r2 × h (4

Java est un langage de programmation populaire qui peut être appris aussi bien par les développeurs débutants que par les développeurs expérimentés. Ce didacticiel commence par les concepts de base et progresse vers des sujets avancés. Après avoir installé le kit de développement Java, vous pouvez vous entraîner à la programmation en créant un simple programme « Hello, World ! ». Une fois que vous avez compris le code, utilisez l'invite de commande pour compiler et exécuter le programme, et « Hello, World ! » s'affichera sur la console. L'apprentissage de Java commence votre parcours de programmation et, à mesure que votre maîtrise s'approfondit, vous pouvez créer des applications plus complexes.
