In Java, we know that == is used to compare values for equality, and equals is used to compare strings for equality. The = = and equals actually is what?
The = = comparison
The comparison is a reference to an object
Java’s basic types store “values” directly in stack memory
So when we compare basic types, it is possible to use == to compare values for equality
Equals to compare
The equals implementation in the Object class is also a reference to the comparison Object. Check the equals document for more information
public boolean equals(Object obj) {
return (this == obj);
}
Copy the code
So why do we get what we want when we compare strings?
This is because the String class overrides equals. The equals source code for String is as follows
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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;
}
Copy the code
Similarly, other wrapper classes implement equals overrides
String comparison
Now let’s test the string comparison
public class Test{
public static void main(String[] args) throws ParseException {
String strA = new String("abc");
String strB = new String("abc");
System.out.println("strA==strB? "+(strA==strB)); //strA==strB? false
System.out.println("strA.equals(strB)? "+strA.equals(strB)); //strA.equals(strB)? true
System.out.println("strA hashCode:"+strA.hashCode()); //strA hashCode:96354
System.out.println("strB hashCode:"+strB.hashCode()); //strB hashCode:96354
String strC = "abc";
String strD = "abc";
System.out.println("strC==strD? "+(strC==strD)); //strC==strD? true
System.out.println("strC.equals(strD)? "+strC.equals(strD)); //strC.equals(strD)? true
System.out.println("strC hashCode:"+strC.hashCode()); //strC hashCode:96354
System.out.println("strD hashCode:"+strD.hashCode()); //strD hashCode:96354
System.out.println("strA==strC? "+(strA==strC)); //strA==strC? false
System.out.println("strA.equals(strC)? "+strA.equals(strC)); //strA.equals(strC)? true}}Copy the code
As you can see, when we use the String generated by new String(), the references to the two objects are different. When a literal is assigned to a String variable, the reference is the same
This is because the virtual machine pools the determined string constants into the constant pool, so the string ABC is already in the string constant pool before the main() method is run. When we use new to create a new String, we return a reference to the new String in the heap if there is a String in the constant pool. If no, the corresponding String is created in the constant pool and a reference to the String is given to the newly created String in the heap. If a literal assignment is used directly, a reference to the string in the constant pool is returned.
So strA and strB are both references to their own objects in the heap, but their respective objects point to the same string reference. Both strC and strD are references to ABC in the constant pool
For an in-depth understanding, see the following article
String Would you? Don’t still come in!! Wait for me. Where are you guys? !!!!!!!!!
In the above code, we can observe that the hashCode of strA strB strC strD is consistent. Until then I thought the hash value of their reference should be the memory address to which the reference refers. Note that this is wrong.
Check out the hashCode() source code below
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode(a) {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
Copy the code
As you can see, the hash value is calculated by the formula h = 31 * h + val[I], so when we pass in the same string, we get the same hash value
The comparison of the Integer
public class Test{
public static void main(String[] args) throws ParseException {
int a = 1;
int b = 1;
System.out.println(a==b); //true
Integer objectA = 2;
Integer objectB = 2;
System.out.println(objectA==objectB); //true
System.out.println(objectA.equals(objectB)); //true}}Copy the code
Why do two Integer objects compare with == and get true? This is because Integer internally maintains an IntegerCache. The default cache range is [-128, 127], so values between [-128, 127] are == and! = comparisons can also give correct results, but comparisons using relational operators are not recommended. See the Integer class source code in the JDK
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if(integerCacheHighPropValue ! =null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache(a) {}}Copy the code
reference
HashCode () method source code analysis
Why do I have to use equals when comparing two Integers? Don’t use the = =
Talk about Equals and == in Java
Thinking in Java Chapter 4