In-depth equals Method
The importance of the equals method does not need to be repeated. As long as the two objects you want to compare do not want to be the same object, you should implement
The equals method allows objects to be compared using conditions that you think are equal.
The following content is only the API specification and does not have much profound significance. But the reason why I listed it first is that
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, and the O and O1 do not change, any subsequent calls
Are all set up.
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, only the same object is, The equals method returns
True, which is often referred to as reference comparison rather than Value Comparison. This strict implementation has no practical significance,
Therefore, in a specific subclass (relative to an object), if we want to compare the object values, we must implement our own
Equals method.
Let's take a look at the following 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 the standard implementation of Java. Text. fieldposition in JDK, and there seems to be nothing to say.
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 have an asymmetric equals algorithm. Where is the problem? (brain teasers: Of course, the JDK implementation bug )?
I believe that too many programmers (except those who do not know how to implement the equals method) are implementing the equals method.
The instanceof Runtime is used for short-circuit optimization. I have used it for a long time.
Too many tutorials and documents are misleading. Some programmers who have a better understanding may know the possibility of such optimization.
Some of them are incorrect, but they cannot be found. The other extreme is that hardcore experts who know this technical defect propose not
Sample application.
We know that "normally" to compare two objects, they "should" be of the same type. So first use instanceof
Run character for short circuit optimization. If the compared object is not of the same type as the current object, false is returned, but the fact
So if the sub-class o instanceof parent class always returns true, then certainly
There will be no short-circuit optimization. The following comparison may result in multiple situations. One is that exceptions cannot be formed into subclasses, and the other is thrown.
The private member of the parent class does not inherit from the quilt class and cannot be compared. In addition, the above asymmetric comparison is formed. Possible
There will be too many cases.
So, isn't it possible to use the instanceof operator for optimization? The answer is no. Many implementations in JDK are positive.
Indeed, if a class is final and knows 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 explain which class, but a team member adds
Added the following annotations:
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 ......)
For non-final classes, how does one 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
If the equals method is not re-implemented, obj. getclass () is definitely not equal to xxxcalss. class when the subclass is compared,
That is, the equals of the subclass will be invalid, So If (obj. getclass ()! = This. getclass () return false; is positive
True comparison.
Note that if (obj. getclass ()! = This. getclass () return false; only to make the subclass work normally.
If the comparison is correct after inheritance, it should not be considered by the parent class. It is provided by the subclass implementer. In fact, it is only called in the subclass.
Super. Equals can first compare the private variables of the parent class, and then compare the class members of the subclass extension. Use dynamics in the parent class
Reflection compares all the members of the access subclass. Although this allows the subclass to directly use equals, it violates the design principles.
You think too far for the future.
Another quick check is if (this = OBJ) return true;
Are the two objects that the equals method must compare must be of the same type? I used "general" above, which is also the vast majority of Programs
But in some special cases, we can compare different types, which does not violate the rules. But in this special case
It is very rare. an inappropriate example is that the equals of integer classes can be compared with sort, and their values are not
Is the same mathematical value. (In fact, this is not the case in JDK APIs, so I am not saying it is an inappropriate example)
After completing quick check, we need to truly implement what you think is "equal ". If the implemented object is equal, it is not too high
For example, if you implement the "people" 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, then
How to Implement equals?
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 );
}
}
The last point about the equals method is: If you overwrite the equals method yourself (it should be a crawler), then one at the same time
The hashcode () must be rewritten to be 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), what is null after I put (Pn, "I love you"); get (pn1?
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.
Okay, take a rest. Take a break ................