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