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

java.lang.reflect.Method and Constructor hashCode implementation ignores significant properties

XMLWordPrintable

      A DESCRIPTION OF THE PROBLEM :
      The implementation of 'hashCode' in [java.lang.reflect.Method] only incorporates the declaring class and the method name. Consequently, it's relatively common for multiple method in any given class that produce the same hash code. This characteristic means that [Method] objects cannot be used as map keys. Beyond this dearth of incorporated properties, the algorithm itself (XOR'ing the hash codes of the declaring class and method name) is non-standard and could conceivably result in collisions for methods with different names in separate classes.
      However, the implementation of 'equals' considers declaring class, method name, return type, and parameter type when comparing [Method] objects. This seems a sensible set of factors to consider.
      Given that the implementation is documented and has been unchanged for a very long time, it seems unlikely that the algorithm employed by the 'hashCode' method of [java.lang.reflect.Method] will ever be revised, but perhaps it would be appropriate to add a warning to the JavaDoc regarding the unsuitability of the result of this method for purposes where some degree of uniqueness is required (e.g. - as map keys). Perhaps this message could also suggest the 'toString' method as a potential alternative for such purposes.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Create a Java project with the class shown below.
      Run the defined "main" method.
      Examine the method signatures and hash codes.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      For different method signatures, I expect to get different method hash codes
      ACTUAL -
      Methods with the same names in a single class return the same hash codes:

      Static foo toString: public static void com.mkyong.hashing.App.foo()
      Static foo hashCode: -1031059211
      Instance foo toString: public java.lang.String com.mkyong.hashing.App.foo(java.lang.String)
      Instance foo hashCode: -1031059211


      ---------- BEGIN SOURCE ----------
      package com.mkyong.hashing;

      import java.lang.reflect.Method;

      public class App
      {
          public static void main( String[] args ) throws NoSuchMethodException, SecurityException
          {
              Method staticFoo = App.class.getDeclaredMethod("foo");
              Method instanceFoo = App.class.getDeclaredMethod("foo", String.class);

              System.out.println("Static foo toString: " + staticFoo.toString());
              System.out.println("Static foo hashCode: " + staticFoo.hashCode());
              System.out.println("Instance foo toString: " + instanceFoo.toString());
              System.out.println("Instance foo hashCode: " + instanceFoo.hashCode());
          }

          public static void foo() {
              System.out.println( "public static void foo()" );
          }

          public String foo(String bar) {
              System.out.println( "public java.lang.String foo(java.lang.String) got argument: " + bar );
              return bar;
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      For my own purposes, I've chosen to use the output of the 'toString' method as my map key.

      FREQUENCY : always


            liach Chen Liang
            webbuggrp Webbug Group
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: