Java comes into effect on Tuesday! Comply with the `hashCode` contract

Today ’s topic coincides with last week ’s topic. This week we are talking about the hashCode function. Just like the function we discussed last week, this method also has a contract, although it is relatively simple, it should be followed. Like the signature, it takes no parameters and returns an integer. So let us sign the contract:

  • If the object has not been changed, the value returned from the function should remain unchanged. If two objects are actually equal, their hash codes must be the same. (This is more of a non-requirement.) Given that two objects are actually not equal, there is no need to have different hash code values.

In this way, you can see that the hash code is closely related to equality. The second requirement is the most broken requirement. If you do not implement a hash code function, two effectively equivalent objects may not have the same value returned by the function. So let us look at an example:

Map<Address, String> addressBook = new HashMap<>();
addressBook.put(new Address("123","Foggy Lane" "Made Up City", "USA"), "James");
addressBook.get(new Address("123","Foggy Lane" "Made Up City", "USA"));

Given the above example, it is expected that the third line will return "James", but if the hash code function is incorrectly written, it will return a null value.

Therefore, let us write the simplest legal hash code function:

@Override
public int hashCode() {
  return 42;
}

Yes, according to the contract, this is a fully effective hash code function. If it is called multiple times on the same object, it always returns the same thing; for functionally equivalent objects, it returns the same value; for two functionally equivalent objects, it returns the same hash code. . However, even if it complies with the contract, the value returned does not change, which is a terrible idea and may cause a significant performance degradation. For example, in terms of performance, the above hash code function will effectively convert HashMap into a linked list.

There must be a better way, and it does exist. Effective Java provides us with a way to create solid hash code functions.

  1. Declare the integer naming result and initialize it to the value of the first valid field of the object (reminder "valid field" refers to the field that participates in the decision when two objects are equal), as calculated in step 2. For every remaining significant field, do the following calculate a hash code for this integer field. If the field is the original field, then use the boxed version of the field to calculate the hashCode function. For example: Double.hashCode (value) If the field is an object reference, call integer o that object's hashCode function. For null, use the value 0 if it is an array, then treat each important element as a separate field or use Arrays.hashCode if they are all important. Combine the hash code you just calculated with the result as follows: result = 31 * result + newFieldHashcode return result

If you follow the above algorithm correctly, you should calculate a reliable hash code. The advantage of this algorithm is that the order of operations is important, so a better allocation can be achieved. Multiplying by 31 is good because it is an odd prime. Odd numbers help integer overflow, while prime numbers are just because prime numbers are cool. In all reality, it sounds like it has become a standard. Let's take a look at our new address hashCode function.

@Override
public int hashCode() {
  int result = streetAddress.hashCode();
  result = 31 * result + road.hashCode();
  result = 31 * result + country.hashCode();
  return result;
}

Quite simple, but effective. Is there an easier way to write these functions? of course. An example is the use of Objects.hashCode (significantField1, identificationField2, ...). Very good, because it is a one-line hashCode function. The downside is that its performance is worse than the previous example. But I think the best way is to use something like Lombok. Lombok implemented the @EqualsAndHashCode annotation through it. The maintainers of Lombok are very happy to force equal to hashCode.

Finally, let's discuss some hash codes to remember:

  • Always overwrite hash codes when you overwrite equal to include all values ​​in use equal to hash codes as part of the calculation Don't share outside the function how the hash code is calculated, it unnecessarily can tie you to a sub-par implementation.

from: https://dev.to//kylec32/effective-java-tuesday-obey-the-hashcode-contract-3onl

Published 0 original articles · liked 0 · visits 634

Guess you like

Origin blog.csdn.net/cunxiedian8614/article/details/105691244