Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8252556

deepHashCode may be improved to generate consistent hash code

XMLWordPrintable

    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      The current implementation of deepHashCode generates different hash codes for the exact same object array running on different VM executions. This behaviour happen only when given object array contains an Enum value somewhere in given object tree. The .hashCode() method of Enum classes may generate by definition different hash codes and therefore this is not a bug (see javadoc of Object.hashCode() : "This integer need not remain consistent from one execution of an application to another execution of the same application.") . But a consistent hash code is almost strictly required by cache key generator implementations.

      Changing the behaviour of Enum.hashCode() has been already suggested here (https://bugs.openjdk.java.net/browse/JDK-8050217) but unfortunately revoked. I understand the backward compatibility considerations but Enum.hashCode() may actually return "name based" hash code and this will always generate a collision free but consistent hash code.

      If this is not possible I suggest to change the behaviour of deepHashCode as follows:

          public static int deepHashCode(Object a[]) {
              if (a == null)
                  return 0;

              int result = 1;

              for (Object element : a) {
                  final int elementHash;
                  final Class<?> cl;
                  if (element == null)
                      elementHash = 0;
                  else if (element.getClass().isEnum())
                      elementHash = ((Enum<?>)element).name().hashCode();
                  else if ((cl = element.getClass().getComponentType()) == null)
                      elementHash = element.hashCode();
                  else if (element instanceof Object[])
                      elementHash = deepHashCode((Object[]) element);
                  else
                      elementHash = primitiveArrayHashCode(element, cl);

                  result = 31 * result + elementHash;
              }

              return result;
          }

      The following additional two lines (see also above code snippet) checks if the current array element is an Enum and in that case it uses the name value of the Enum to generate hash code.

                  else if (element.getClass().isEnum())
                      elementHash = ((Enum<?>)element).name().hashCode();

      If this change is too implicit and may cause compatibility problems, you can add an overloaded deepHashCode method with an additional boolean flag to use name based enum hash code generation such as:

      public static int deepHashCode(Object a[], boolean useEnumName) { .. }

      Thank you.


            smarks Stuart Marks
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: