directory

  • Data types in Java
  • When to use relational operators= =When do you use equals?
  • equalsWhy method, called the null pointer Java lang. NullPointerException?
  • hashCodeWhat does method do? HashCode equals?
  • Why must every class that overrides equals also override hashCode?

The data type

Data types in Java fall into two categories:

1. Basic data types (raw data types)

Byte, short, char, int, long, float, double, Boolean comparison between them, the double equal sign (= =), basic data types is that they value.

2. Reference types (classes, interfaces, arrays)

When they compare (==), they compare where they are stored in memory, objects are stored in the heap, and references to objects are stored in the stack. It follows that ‘==’ compares the address value in the stack when the object being compared is a reference type.


The relational operator ==

The relational operators included in Java are less than (<), greater than (>), less than or equal to (<=), greater than or equal to (>=), equal to (==), and not equal to (! =).

= = and! = applies to all objects, but these two operators usually cause problems when comparing objects:

Here == and! = compares references to objects. Although the contents of the objects are the same, the references to the objects are different, saying n1==n2 is false.

        Integer n1 = new Integer(47);
        Integer n2 = new Integer(47);
        
        System.out.println(n1 == n2);  //falseSystem.out.println(n1 ! = n2);//true
Copy the code

Here == is comparing the primitive data type, so it will compare the values for equality. So n1 == n2 prints true.

        int n1 = 100;
        int n2 = 100;

        System.out.println(n1 == n2);  //trueSystem.out.println(n1 ! = n2);//false
Copy the code

The equals method

By default, the equals method of an Object calls the equals method of the Object class. The source code is as follows:

    public boolean equals(Object obj) {
        return (this == obj);  
    }
Copy the code

Note that we are still using ==, and we are comparing reference objects, so we are comparing addresses.


In the second case, the equals method of the object is overridden. For example, a String object. The source code is as follows:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;// Return the same object directly
        }
        if (anObject instanceof String) {// The String starts judging the content.
            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) {// Compare character by character, false if there are unequal characters
                    if(v1[i] ! = v2[i])return false;
                    i++;
                }
                return true; }}return false;
    }

Copy the code

The equals() method is used to compare the contents of objects, not references to objects, but to determine whether objects are equal


avoidequalsMethod to declare a null pointer

Equals (a,b). In JDK7, we added a Objects utility class that provides methods to manipulate Objects. It consists of static utility methods. These methods are null-save (null-pointer safe) or null-tolerant (null-pointer tolerant) and are used to evaluate the object’s Hashcode, return the string representation of the object, and compare two objects.

By default, the equals method of an Object is not overridden. Instead, the equals method of the Object class is called

So let’s write an example of an error:

        A a = null;// Suppose I receive a config object and I don't know if it is empty, so I compare it
        boolean r = a.equals(new B());
        System.out.println(r); / / output Java. Lang. NullPointerException
Copy the code

Because of our negligence, we did not verify the parameters after receiving them, resulting in the call to equals to return the null pointer.

// Other examples are:
null.equals("Java treasure dian");  //NullPointerException

"Java treasure dian".equals(null);  //false Returns only if equals is not Null

null.equals(null);  //NullPointerException
Copy the code

Objects.equals(a,b) does not return a Null pointer if both sides are Null

 Objects.equals(null."Java treasure dian");  //false
 
 Objects.equals("Java treasure dian".null);  //false
 
 Objects.equals(null.null);  //true
Copy the code

Look at the source code for objects.equals, which tolerates null Pointers

    public static boolean equals(Object a, Object b) {
        return(a == b) || (a ! =null && a.equals(b));
    }
Copy the code

HashCode () method

A Hash is actually a person’s name, named after him because he came up with the idea of a Hash algorithm. Hash algorithm, also known as hash algorithm, refers to the data according to a specific algorithm directly assigned to an address, commonly understood as a method of creating a small digital “fingerprint” from any kind of data.

In Java, objects do not override the hashCode() method by default. The Object class is used.

  public native int hashCode(a); // It is a native method.

Copy the code

The hashCode method defined by the Object class returns different integers for different objects. (This is done by converting the object’s internal address to an integer.)

Example:

        Config config1 = new Config();
        Config config2 = new Config();

        System.out.println(config1.hashCode());  / / 1128032093

        System.out.println(config2.hashCode());  / / 1066516207

        System.out.println(config1.equals(config2));  //false
Copy the code

HashCode and equals

They are both methods in the Object class, which is the base of all classes, so they can be overridden in any class.

  • Rule 1: If x.equals(y) returns “true”, the hashCode() of x and y must be equal;

  • Principle 2: If x.equals(y) returns “false”, the hashCode() of x and y may or may not be equal;

  • Rule 3: If the hashCode() of x and y are not equal, then x.equals(y) must return “false”;

  • Rule 4: Generally speaking, equals is called by the user. Hashcode is not called by the user.

  • Principle 5: When an object type is an element of a collection object, the object should have its own equals() and hashCode() designs, and follow the previous principles.

During Java application execution, the same integer must be consistently returned when the hashCode method is called on the same object multiple times, provided that the information used to compare the objects to Equals has not been modified. The integer need not be consistent from one execution of an application to another execution of the same application.

If two objects are equal according to equals(Object), then calling the hashCode method on each of the two objects must produce the same integer result.

If two objects are not equal according to equals(java.lang.object), calling the hashCode method on either Object does not require that different integer results be generated. However, programmers should be aware that generating different integer results for unequal objects can improve hash table performance.


Why must every class that overrides equals also override hashCode?

In every class that overrides equals methods, hashCode methods must also be overridden. Failing to do so would violate the general convention of Object.hashCode and result in the class not working properly with all hashed based collections

In order to understand the application of hashCode, we must first understand the container in Java, because hashCode is only useful in data structures that require hash algorithms, such as HashSet, HashMap..

Let’s take hashMap as an example:

A HashMap is a structure that stores data made up of arrays and linked lists. To determine where the data is stored in the array, use hashCode to calculate where it is stored. If there are conflicts, equals is called to compare them. If they are different, they are added to the end of the list, and if they are identical, they are replaced. There are several other steps in the process, which can simply be considered as hashCode to determine the location:

public V put(K key, V value) {
	    // If the hash table is not initialized, initialize it
	    if (table == EMPTY_TABLE) {
	        // Initialize the hash table
	        inflateTable(threshold);
	    }
	 
	    PutForNullKey is called when the key is null, and null is stored in the first position of the table. This is why HashMap allows null
	    if (key == null) {
	        return putForNullKey(value);
	    }
	 
	    // Computes the hash value of the key
	    int hash = hash(key);
	    // Locate the specified slot in the entry array according to the hash value of the key and the length of the array
	    int i = indexFor(hash, table.length);
	    // Get the entry of the store location. If the entry is not empty, the list of the entry is traversed
	    for(Entry<K, V> e = table[i]; e ! =null; e = e.next) {
	        Object k;
	        // Check whether the key exists by using the key's hashCode and equals methods. If so, replace the old value with the new value and return the old value
	        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
	            V oldValue = e.value;
	            e.value = value;
	            e.recordAccess(this);
	            returnoldValue; }}// The number of changes increases by 1
	    modCount++;
	    // If the list cannot be found or the key does not exist after traversing the list, a new Entry is created and added to the HashMap
	    addEntry(hash, key, value, i);
	    return null;
	} 
Copy the code

In the above method, we can see that the subscript of the array is xor based on the return value of the passed element hashCode method and the specific value:

static int indexFor(int h, int length) {
        // Hash and length-1 to compute the index
        return h & (length - 1);
    }
Copy the code

Back to our question: Why should every class that overwrites equals also have to overwrite hashCode?

If you override equals and the implementation of hashCode does not, then the class’s hashCode method is the default hashCode method of Object. Since the default hashCode method is a hash derived from the memory address of the Object, It is possible that two objects are clearly “equal,” but hashCode is different.

This way, if you save one of them as a key in a hashMap, hasoTable, or hashSet, and then “equal” the other as a key, you won’t find them at all. The HashSet and HashMap cannot work properly.

Such as: Class A overwrites the equals method, but not the hashCode method. A1 and A2 use the equals method to equal each other. They are not the same hashcode, so we overrode equals and tried to rewrite hashcode so that they would have the same hashcode if they were equal.


conclusion

  • == When you compare basic data types, you compare values

  • When you compare a reference data type, you compare the reference address of an object

  • The equals method of objects, without overwriting it, uses == and compares the reference addresses of the objects

  • The equals method of an object, when overridden, is used to compare the equals contents of the object. The implementation can be generated using an IDE or custom implementation.(For example, the String class overrides the equals method to compare characters one by one.)

  • Objects.equals(a,b); objects.equals (a,b); objects.equals (a,b)

  • Hashcode is used by the system to quickly retrieve objects

  • If you override the equals method, you must also override the hashCode method. Otherwise, hashsets, hashmaps, and other containers that depend on HashCode will not work properly

Concern public number: Java baodian