}
The importance of the equals method does not need to be repeated. If you want to compare whether two objects are the same object, you should implement the equals method so that the objects can be compared using conditions that you think are equal.
The following content is only the API specification, which has no profound significance. But I listed it first because these specifications are not guaranteed in reality.
1. For any reference type, O. Equals (o) = true is true.
2. If O. Equals (O1) = true is true, o1.equals (o) = true must also be true.
3. If O. Equals (O1) = true and O. Equals (O2) = true, then
O1.equals (O2) = true is also true.
4. If the first call o. Equals (O1) = true is true, any subsequent call will be valid if O and O1 are not changed.
5. O. Equals (null) = true is not true at any time.
The above rules are not the most complete statement. For details, see the API documentation. for the object class, it provides the most rigorous implementation, that is, the equals method returns true only when it is the same object, that is, the reference comparison that people often say is not the value comparison. this strict implementation has no practical significance, so in the specific subclass (relative to the object), if we want to compare the object values, we must implement our own equals method. let's take a look at the following section.Program:
Public Boolean equals (Object OBJ)
{
If (OBJ = NULL) return false;
If (! (OBJ instanceof fieldposition ))
Return false;
Fieldposition Other = (fieldposition) OBJ;
If (attribute = NULL ){
If (other. Attribute! = NULL ){
Return false;
}
}
Else if (! Attribute. Equals (other. Attribute )){
Return false;
}
Return (beginindex = Other. beginindex
& Amp; endindex = Other. endindex
& Field = Other. Field );
}
This is Java in JDK. text. there seems to be nothing to say about the Standard Implementation of fieldposition. I believe that most or most programmers believe that this is the correct and legal equals implementation. after all, it is the jdk api implementation. let's talk about it as a matter of fact:
Package debug
; Import java. Text .*;
Public class test {
Public static void main (string [] ARGs ){
Fieldposition fp = new fieldposition (10 );
Fieldposition FP1 = new mytest (10 );
System. Out. println (FP. Equals (FP1 ));
System. Out. println (fp1.equals (FP ));
}
}
Class mytest extends fieldposition {
Int x = 10;
Public mytest (int x ){
Super (X );
This. x = X;
}
Public Boolean equals (Object O ){
If (O = NULL) return false;
If (! (O instanceof mytest) return false;
Return (mytest) O). x = This. X;
}
}
Run the command to see what will be printed:
System. Out. println (FP. Equals (FP1); print true
System. Out. println (fp1.equals (FP); print flase
Two objects with asymmetric equalsAlgorithm. Where is the problem? (brain teasers: Of course, the JDK implementation bug )? I believe there are too many programmers (except those who do not know how to implement the equals method) who have used the instanceof operator to perform short-circuit optimization when implementing the equals method, I have used it for a long time.
Too many tutorials and documents are misleading. Some programmers who have a better understanding may know that such optimization may be wrong but cannot find the key to the problem. Another extreme is that hardcore experts who know this technical defect propose not to apply it like this. We know that "normally" to compare two objects, they "should" be of the same type. Therefore, short-circuit optimization is implemented using the instanceof operator. If the compared object is not of the same type as the current object, false is returned without comparison.
But in fact, "The subclass is an instance of the parent class", so if the subclass o instanceof parent class always returns true, then there will certainly be no short-circuit optimization, the following comparison may result in multiple situations: one is that an exception cannot be thrown when it is modeled as a parent class, and the other is that the private member of the parent class cannot be compared without the inheritance of the quilt class, in addition, the above asymmetry comparison is formed. There may be too many cases.
So, isn't it possible to use the instanceof operator for optimization? The answer is no. There are still many implementations in JDK that are correct. If a class is final, knowing that it cannot have sub-classes, why not use instanceof for optimization? In order to maintain Sun's development team's reputation, I do not describe which class, but a team member added the following comment when using this method for optimization:
If (this = OBJ) // quick check
Return true;
If (! (OBJ instanceof xxxxclass) // (1) same object?
Return false;
There may be some questions, but I don't know how to do it (I don't know why I didn't call me...). So for non-final classes, how do I perform quick check?
If (obj. getclass ()! = Xxxclass. Class) return false;
Compared with the Class Object of the compared object and the class of the current object, it seems that there is no problem. However, if the subclass of this class does not implement the equals method again, when the subclass is compared, OBJ. getclass () is certainly not equal to xxxcalss. class, that is, the equals of the subclass will be invalid, so
If (obj. getclass ()! = This. getclass () return false;
Is the correct comparison. Another quick check is if (this = OBJ) return true;
Do two objects compared by the equals method must be of the same type? I used "regular" above, which is also the wish of the vast majority of programmers, but in some special cases, we can compare different types, which does not violate the rules. However, this special case is very rare. an inappropriate example is that the equals of the integer class can be compared with sort to compare whether their values are of the same mathematical value. (In fact, this is not the case in JDK APIs, so I am saying it is not an appropriate example.) After completing quick check, we need to truly implement what you think is "equal ". There is no high requirement for implementing object equality. For example, if you implement the "person" class, you can think that they are equal as long as the names are the same, and other sex, can be ignored. This is not fully implemented, but if it is fully implemented, that is, all attributes must be the same, how to implement the equals method?
Class human {
Private string name;
Private int ago;
Private string sex;
....................
Public Boolean equals (Object OBJ ){
Quick check .......
Human Other = (human) OJB;
Return this. Name. Equals (other. Name) & this. ago = ohter. ago & this. Sex. Equals (other. Sex );
}
}
This is a complete implementation. However, sometimes the equals implementation is implemented in the parent class, and equals can be correctly implemented after the quilt class inherits.
At this time, you do not know what attributes the subclass has extended, so the above method cannot fully implement equals.
A good method is to use reflection to fully implement equals:
Public Boolean equals (Object OBJ ){
Quick check .......
Class C = This. getclass ();
Filed [] FDS = C. getdeclaredfields ();
For (filed F: FDs ){
If (! F. Get (this). Equals (F. Get (OBJ )))
Return false;
}
Return true;
}
For convenience of illustration, the above implementation omitted the exception. Such implementation is placed in the parent class, which ensures that the equals of your subclass can work correctly as you wish. The last point about the equals method is: If you overwrite the equals method yourself (it should be a crawler), you must overwrite the hashcode () at the same time (). this is a specification, otherwise .............
Let's take a look at this example:
Public final class phonenumber {
Private Final int areacode;
Private Final int exchange;
Private Final int extension;
Public phonenumber (INT areacode, int exchange, int extension ){
Rangecheck (areacode, 999, "Area Code ");
Rangecheck (exchange, 99999999, "Exchange ");
Rangecheck (extension, 9999, "extension ");
This. areacode = areacode;
This. Exchange = exchange;
This. Extension = extension;
}
Private Static void rangecheck (INT Arg, int Max, string name ){
If (ARG <0 | arg> MAX)
Throw new illegalargumentexception (name + ":" + Arg );
}
Public Boolean equals (Object O ){
If (O = This)
Return true;
If (! (O instanceof phonenumber ))
Return false;
Phonenumber Pn = (phonenumber) O;
Return Pn. Extension = extension & Pn. Exchange = exchange & Pn. areacode = areacode;
}
}
Note that this class is final, so there is no problem with this equals implementation. Let's test:
Public static void main (string [] ARGs ){
Map Hm = new hashmap ();
Phonenumber Pn = new phonenumber (123,389 42, 230 );
Hm. Put (Pn, "I love you ");
Phonenumber pn1 = new phonenumber (123,389 42, 230 );
System. Out. println (PN );
System. Out. println ("Pn. Equals (pn1) is" + Pn. Equals (pn1 ));
System. Out. println (Hm. Get (pn1 ));
System. Out. println (Hm. Get (PN ));
}
Since Pn. Equals (pn1), why is get (pn1) null after I put (Pn, "I love you?
the answer is that their hashcode is different, and hashmap uses hashcode as the primary key. Therefore, the specification requires that if two objects return true when performing equals comparison, their hashcode requires that they return equal values.