Java must make clear the usage and difference between = = and equals and hashcode

Do a little exercise before viewing this article

Question 1:

Check whether the value of s1 == s2 is true or fasle?

 String s1 = "abc";
 String s2 = "abc";
 System.out.println(s1 == s2);

The answer is: true

Question 2:

Check the program. Is the value of s1 == s2 true or fasle?

 String s1 = "abc";
 String s2 = "ab"+"c";
 System.out.println(s1 == s2);

The answer is: true

Question 3:

Check the following program. Is the value of s1 == s2 true or fasle?

 String s1 = "abc";
 String s2 = "ab";
 s2 = s2+"c";
 System.out.println(s1 == s2);

The answer is: false

Question 4:

See the following procedure, S1 Is the value of equals (S2) true or false?

 String s1 = "abc";
 String s2 = "ab";
 s2 = s2+"c";
 System.out.println(s1.equals(s2));

The answer is: true

analyse:

A single "abc" and "ab"+"c" constant light operation will store and create a reference object in the constant light pool, and then s1 and s2 point to the address of the variable in the constant light pool

And s2+"c" is the operation of object and constant light. Why?

When we use javap - V XXX Class found when checking the bytecode

         13: invokespecial #14                 // Method java/lang/StringBuilder."<init>":()V
         16: ldc           #15                 // String s1 =
         18: invokevirtual #16                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
         21: aload_1
 ​

When our object operates with Chang Liang, a StringBuilder will be created first. At this time, the address of s2 will certainly change. If = = is the address of the comparison object, the value of question 3 is false

The value after equals is true because the underlying String overrides the equals() method of Object

Extension:

   String a = new String("ab"); // A is a reference
   String b = new String("ab"); // b is another reference, and the content of the object is the same
   System.out.println(a==b);

I can try to analyze a wave!

In Java==

==

For basic values: compare values

For reference objects, the object address is compared

Because Java only passes values, for = =, whether comparing basic data types or variables referring to data types, the essence of the comparison is the value, but the value stored in the reference type variable is the address of the object.

equals() method

The equals() method is in the Object class, and the Object class is the direct or indirect parent of all classes, so all classes have the equals() method

The equals() method cannot be used on variables of basic data type. It can only be used to judge whether two objects are equal. You can customize the equals() method

equals() method in Object

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

The default comparison is the address, similar to = =

hashCode() method

Introduction: the hashCode() method is used to return the object hash code, also known as hash code; It actually returns an int positive integer. This method is supported to facilitate hash tables, such as Java util. HashMap (from the source code note), the hash code determines the index position of the object in the hash table

Like the equals() method, it comes from the Object class, so all classes have this method!!

View the definition of hashCode() by Object class:

     public native int hashCode();

It can be found that it is a local method, which is implemented in C language or C + +

Requirements (from jdk source code):

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

  2. During the execution of a Java application, it can only be called multiple times on the same object. The hashCode() method must always return the same integer, provided that the information used in the equals() comparison of the object has not been modified This integer does not need to be consistent from one execution of an application to another execution of the same application

  3. This is not necessary: if the two objects are based on the unequal equals(Object) method, then calling hashCode() must produce different integer results in different ways of the two objects, (the hashCode values of different objects can be the same), however, Programmers should be aware that generating different integer results for unequal objects may improve the performance of the hash table (try to ensure that the hashcode value of each object is different, because it can improve the performance of the hash table)

Extension:

Hash table stores key value pairs. Its feature is that it can quickly retrieve the corresponding value according to the 'key' This makes use of hash code! (you can quickly find the required object)

Why do I have to override the hashCode method when overriding equals?

If two objects are equal, the hashcode must be the same. If the two objects are equal, calling the equals method on the two objects returns true. However, two objects have the same hashcode value, and they are not necessarily equal. Therefore, if the equals method is overridden, the hashcode method must also be overridden.

The default behavior of hashCode() is to generate unique values for objects on the heap. If hashCode() is not overridden, the two objects of the class will not be equal in any case (even if they point to the same data)

Why do two objects have the same hashcode value and they are not necessarily equal?

Because the hash algorithm used by hashCode() may just let multiple objects return the same hash value. The worse the hash algorithm, the easier it is to collide, but this is also related to the characteristics of data value domain distribution (the so-called collision means that different objects get the same hashCode).

We just mentioned the HashSet. If the HashSet has multiple objects in the same hashcode during comparison, it will use equals() to judge whether it is really the same. In other words, hashcode is only used to reduce the search cost.

Relationship between memory address and hashcode value of Java object

Remember one point: memory addresses are completely different from hashcode, and there is no comparability

In order to compare the memory address of Java objects with hashcode, we must find a way to obtain these two values

Java cannot directly access the bottom of the operating system, but through local methods. Unsafe class provides hardware level atomic operations. In Java, the address of the object in memory is variable, so the obtained memory address may change. To obtain the memory address, you can only obtain it through the unsafe method. See the code below for details

 package com.fagejiang.test;
 ​
 import sun.misc.Unsafe;
 ​
 import java.lang.reflect.Field;
 ​
 /**
  * Memory address acquisition
  *
  * @author Fage talks about Java
  * @version 1.0
  * @date 2021-06-08 18:01
  */
 public class MemoryAddressTest {
     private static Unsafe unsafe;
 ​
     static {
         try {
             Field field = Unsafe.class.getDeclaredField("theUnsafe");
             field.setAccessible(true);
             unsafe = (Unsafe) field.get(null);
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 ​
     public static long addressOf(Object o) throws Exception {
         Object[] array = new Object[]{o};
         long baseOffset = unsafe.arrayBaseOffset(Object[].class);
         //The arrayBaseOffset method is a local method that can obtain the offset address of the first element of the array
         int addressSize = unsafe.addressSize();
         long objectAddress;
         switch (addressSize) {
             case 4:
                 objectAddress = unsafe.getInt(array, baseOffset);
                 //The getInt method obtains the value of the int field corresponding to the offset address in the object
                 break;
             case 8:
                 objectAddress = unsafe.getLong(array, baseOffset);
                 //The getLong method obtains the value of the long field corresponding to the offset address in the object
                 break;
             default:
                 throw new Error("unsupported address size: " + addressSize);
         }
         return (objectAddress);
     }
 ​
     public static void main(String... args) throws Exception {
         String str = "Hello world";
         Object mine = str.toCharArray(); //First convert the string into an array object
         long address = addressOf(mine);
         System.out.println("str Memory address of: " + address);
         System.out.println("str of hashcode: " + str.hashCode());
         // Verify address works - should see the characters in the array in the output
         printBytes(address, 27);
     }
 ​
     public static void printBytes(long objectAddress, int num) {
         for (long i = 0; i < num; i++) {
             int cur = unsafe.getByte(objectAddress + i);
             System.out.print((char) cur);
         }
         System.out.println();
     }
 }
 ​

The output is as follows:

 Connected to target VM, address: ''127.0.0.1:61904',transmission: 'socket''
 str Memory address of: 3983691075
 str of hashcode: -832992604
 #
 # A fatal error has been detected by the Java Runtime Environment:
 #
 #  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006fa1781f, pid=20360, tid=0x00000000000055d4
 #
 # JRE version: Java(TM) SE Runtime Environment (8.0_201-b09) (build 1.8.0_201-b09)
 # Java VM: Java HotSpot(TM) 64-Bit Server VM (25.201-b09 mixed mode windows-amd64 compressed oops)
 # Problematic frame:
 # V  [jvm.dll+0x1e781f]
 #
 # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
 #
 # An error report file with more information is saved as:
 # D:\development\workspace\fagejiang\talk_about_fage\hs_err_pid20360.log
 #
 # If you would like to submit a bug report, please visit:
 #   http://bugreport.java.com/bugreport/crash.jsp
 #
 And goal VM Disconnect, Address is: ''127.0.0.1:61904',transmission: 'socket''
 ​
 The process has ended with exit code 1

Keywords: Java

Added by DaveMate on Wed, 02 Feb 2022 02:12:11 +0200