[Cut constantly, the reason is still messy] Those things about equals and == in Java

Elaborate on equals and ==

1. Originated from Object

We all know that all classes in Java inherit the Object superclass by default, and Object has more than 10 methods. Here we introduce the main ones and toStringmethods .equalshashcode

  • toStingThe method returns " " by default 类名@地址值; we generally rewrite it, and then we can directly print the object to get the rewritten form of the output.

The following highlights equalsand hashcode:

  • equalsThe method compares the object (address) by default, that is, the == operation is performed. If the content needs to be compared, it needs to be rewritten.
  • hashcodeThe default is to return a string of integers based on the object address, which means the same address hashcodeis the same. And it hashcodeis a method in Object, a nativelocal method, indicating that the method is implemented by calling other languages, which is a bit like an interface, and you don't need to implement it yourself.

The following is the relevant source code in the Object class:

 public String toString() {
    
    
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
public boolean equals(Object obj) {
    
    
        return (this == obj);
    }
public native int hashCode();

2, entangled in String

Let's talk about the characteristics java.lang.Stringof neutralization :equalshashcode

String equalsand hashcodeboth are rewritten.

First of all, the hashcode calculates the hash according to the content of the object, so the content of the object is the same, and their hashcode is the same.

public int hashCode() {
    
    
        int h = hash;
        if (h == 0 && value.length > 0) {
    
    
            char val[] = value;
			
            //这种 hash 计算方式不难看出,元素 value 相同 h 会是一样的
            for (int i = 0; i < value.length; i++) {
    
    
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

For strings, equals compares the object contents, which is also due to the specificity of strings.

Then == compares the object address.

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;
    }

3. Code verification

Here is the test code:

public class TEST {
    
    
    public static void main(String[] args){
    
    

        Object o1 = new Object();
        Object o2 = new Object();
        Object o3 = o2;
        System.out.println(o1==o2); //false
        System.out.println(o1.equals(o2)); //false,Object 原生 equals,默认比较地址
        System.out.println(o1.hashCode()==o2.hashCode()); //false,根据地址计算 hash
        System.out.println(o2.hashCode()==o3.hashCode()); //true

        String s1 = "abc";
        String s2 = s1; //常量池优化机制
        String s3 = new String("abc");
        System.out.println(s1==s3); //false 地址不一样,一个在常量池中一个在堆中
        System.out.println(s1.equals(s3)); //true,比较内容
        System.out.println(s2.hashCode()==s1.hashCode()); //true,根据内容计算 hash
        System.out.println(s1.hashCode()==s3.hashCode()); //true
    }

}

4. Override method

In some scenarios, we need to customize the "equal" rule. For example, if we define the same content of the object as equal, we need to override the equals method:

import java.util.Objects;

public class Person {
    
    	
	private String name;
	private int age;
	
    @Override
    public boolean equals(Object o) {
    
    
        // 如果对象地址一样,则认为相同
        if (this == o)
            return true;
        // 如果参数为空,或者类型信息不一样,则认为不同
        if (o == null || getClass() != o.getClass())
            return false;
        // 转换为当前类型
        Person person = (Person) o;
        // 要求基本类型相等,并且将引用类型交给 java.util.Objects 类的 equals 静态方法取用结果
        return age == person.age && Objects.equals(name, person.name);
    }
}
 //对象比较地址,字符串比较内容
 public static boolean equals(Object a, Object b) {
    
    
 //1,对象类型时
 //a==b 为 true,则 true
 //a==b 为 false,则 false;
 //2,string 类型时
 //地址 true,内容 true,则 true
 //地址 false,内容 true,则 true;地址不等内容不等,flase
        return (a == b) || (a != null && a.equals(b));
    }

In some occasions, we also need to rewrite the hashcode. For example, the judgment mechanism of "element equality" in HashSet is to comprehensively consider the hashcode and equals methods; so when we customize the object, we need to rewrite the hashcode and equals methods.

The method rewriting of equals refers to the above example. The following is the rewriting of the hashcode method and the corresponding method source code:

@Override 
public int hashCode() {
    
    
     //仍然调用的是 Objects 的 hash 方法
    //对于这里而言,age 走地址判断;name 走内容判断;所以只要他们内容相同就会返回相同的 hash
        return Objects.hash(name, age);
    }
public static int hash(Object... values) {
    
    
        return Arrays.hashCode(values);
    }
public static int hashCode(Object a[]) {
    
    
        if (a == null)
            return 0;

        int result = 1;
		//仍然走的是 Object 的 hashCode 方法
        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }

Of course, the above rewrite method, the Generate of idea provides a rewrite template, which can be generated with one click.

5. Summary

The hashcode of Object returns the value according to the address, equals compares the address, == compares the address;

The hashcode of String returns the value according to the content, equals compares the content, == compares the address.

That is, Object always compares the address, because String has method overriding, it is the content of comparison. == is actually a comparison address in itself.

Guess you like

Origin blog.csdn.net/qq_40589204/article/details/119394186