网站的备案要求,域名icp备案查询,WordPress样式表修改字体大小,电子商务网站开发成本在我最近的博客文章Arrays.hashCode#xff08;#xff09;与 DZone联合版本的评论中提出了一个有趣的问题。 Objects.hash#xff08;#xff09; “。 该评论的作者建立了一些示例#xff0c;这些示例与我的博客文章中使用的示例相似#xff0c;并且显示出与我看到的结… 在我最近的博客文章Arrays.hashCode与 DZone联合版本的评论中提出了一个有趣的问题。 Objects.hash “。 该评论的作者建立了一些示例这些示例与我的博客文章中使用的示例相似并且显示出与我看到的结果不同的结果。 感谢评论作者抽出宝贵的时间来发表这篇文章因为它带来了Java的细微差别我认为这很值得写博客。 评论作者显示了以下有效的Java语句 int[] arr new int[]{1,2,3,4};
System.out.println(Arrays.hashCode(arr));
System.out.println(Objects.hash(1,2,3,4));
System.out.println(Arrays.hashCode(new Integer[]{new Integer(1),new Integer(2),new Integer(3),new Integer(4)}));
System.out.println(Objects.hash(new Integer(1),new Integer(2),new Integer(3),new Integer(4))); 该评论的作者提到对于所有四个语句运行刚显示的代码的结果都完全相同。 这与我的示例不同在示例中在原始int值数组上调用Arrays.hashCodeint []的结果与在同一原始int值数组上调用Objects.hashObject…的结果不同。 对原始反馈评论的一个答复准确地指出不能保证在不同JVM上生成的哈希码是相同的。 实际上 Object.hashCode方法的Javadoc注释指出我强调了 只要在Java应用程序执行期间在同一对象上多次调用它hashCode方法就必须一致地返回相同的整数前提是不修改该对象的equals比较中使用的信息。 从一个应用程序的执行到同一应用程序的另一执行此整数不必保持一致。 如果根据equalsObject方法两个对象相等则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。 陈述了所有这些内容之后为整数计算的哈希码通常在每次运行之间都是一致的。 原始评论者示例的输出都具有完全相同的值也很有趣。 尽管我可能不希望这些值与示例的值相匹配但是令人惊讶的是评论者提供的所有示例都具有相同的答案。 反馈注释中提供的示例与我的示例之间的区别在于注释者的示例如何为原始int值数组调用Objects.hash(Object...)与我的示例如何调用Objects.hash(Object...)用于原始int值的数组。 在我的示例中我将相同的本地数组传递给所有方法调用。 该注释者的示例将原始int值的显式数组传递给Arrays.hashCode(int[]) 但将各个int元素传递给Objects.hash(Object...)而不是将数组传递给后一个方法。 当我向注释者的示例集中添加另一个示例该示例确实将原始int值数组传递给Objects.hash(Object...)方法时我得到的生成的哈希码与所有其他哈希码不同。 接下来显示该增强的代码。 final int[] arr new int[]{1,2,3,4};
out.println(Arrays.hashCode(int[]): Arrays.hashCode(arr));
out.println(Objects.hash(int, int, int, int): Objects.hash(1,2,3,4));
out.println(Objects.hash(int[]): Objects.hash(arr));
out.println(Objects.hashCode(Object): Objects.hashCode(arr));
out.println(int[].hashCode(): arr.hashCode());
out.println(Arrays.hashCode(Int, Int, Int, Int): Arrays.hashCode(new Integer[]{1,2,3,4}));
out.println(Objects.hash(Int, Int, Int, Int): Objects.hash(1,2,3,4)); 运行注释器提供的代码的经过调整和增强的版本会导致输出带有我添加的示例突出显示 Arrays.hashCode(int[]): 955331
Objects.hash(int, int, int, int): 955331
Objects.hash(int[]): 897913763
Objects.hashCode(Object): 897913732
int[].hashCode(): 897913732
Arrays.hashCode(Int, Int, Int, Int): 955331
Objects.hash(Int, Int, Int, Int): 955331 将输出与生成它的代码进行比较可以看出当将int值数组的元素传递给Arrays.hashCode(int[]) 它与Objects.hash(Object...)生成相同的哈希码值Objects.hash(Object...)方法作为单个元素。 但是我们还可以看到当完整地传递原始int值的数组作为单个数组而不是作为数组的单个元素时 Objects.hash(Object...)方法生成了完全不同的哈希码。 我添加的其他两个示例突出显示是通过直接在数组上调用.hashCode()或通过Objects.hashCode获得等效结果来显示原始int值数组上的“直接”哈希码。 对象 。 [这并非巧合 Objects.hash(Object...)为原始int值数组生成的哈希码比为原始int值数组生成的“直接”哈希码正好大31。 ] 所有这些都指向这里的真正问题通常最好不要将原语数组传递给接受可变参数 通告省略号 的方法。 SonarSource规则浏览器 Java 在RSPEC-3878中提供了有关此内容的更多详细信息。 与规则描述特别相关的是与歧义有关的问题“数组应该是一个对象还是对象的集合” 刚刚提出的问题的答案是当将原始int值数组传递给接受方法Objects.hash(Object...)的变量参数时 整个数组将被视为单个 Object 。 相反当将引用对象的数组例如Integer 传递给相同的方法时它将其视为与数组中的元素传递给它的对象数量相同。 下一个代码清单和相关输出证明了这一点。 package dustin.examples.hashcodes;import static java.lang.System.out;/*** Demonstrates the difference in handling of arrays by methods that* accept variable arguments (ellipsis) when the arrays have primitive* elements and when arrays have reference object elements.*/
public class ArraysDemos
{private static void printEllipsisContents(final Object ... objects){out.println( Ellipsis Object... - Variable Arguments ( objects.length elements): objects.getClass() - objects);}private static void printArrayContents(final Object[] objects){out.println( Array Object[] - Variable Arguments ( objects.length elements): objects.getClass() - objects);}private static void printArrayContents(final int[] integers){out.println( Array int[] - Variable Arguments ( integers.length elements): integers.getClass() - integers);}public static void main(final String[] arguments){final int[] primitiveIntegers ArraysCreator.createArrayOfInts();final Integer[] referenceIntegers ArraysCreator.createArrayOfIntegers();out.println(\nint[]);printEllipsisContents(primitiveIntegers);printArrayContents(primitiveIntegers);out.println(\nInteger[]);printEllipsisContents(referenceIntegers);printArrayContents(referenceIntegers);}
}int[]Ellipsis Object... - Variable Arguments (1 elements): class [Ljava.lang.Object; - [Ljava.lang.Object;2752f6e2Array int[] - Variable Arguments (10 elements): class [I - [I1cd072a9Integer[]Ellipsis Object... - Variable Arguments (10 elements): class [Ljava.lang.Integer; - [Ljava.lang.Integer;7c75222bArray Object[] - Variable Arguments (10 elements): class [Ljava.lang.Integer; - [Ljava.lang.Integer;7c75222b 刚刚显示的示例代码和相关的输出表明期望变量参数的方法将传递给它的原始值数组视为单个元素数组 。 另一方面相同的方法将传递给具有参考对象类型的数组的数组视为具有相同元素数的数组。 考虑到这一点请返回哈希码生成示例由Objects.hash(Object...)为原始int值数组生成的哈希码与由Arrays.hashCode(int[])生成的哈希码不同。 类似地我们现在可以解释为什么对象引用数组导致相同的哈希码而不管调用了哪种方法。 前面我提到过由Objects.hash(Object)生成的哈希码比整个数组的“直接”哈希码高31并非巧合。 这并不奇怪因为Objects.hash(Object...)的OpenJDK实现将Arrays.hashCode(Object[]) Objects.hash(Object...)委托给Arrays.hashCode(Object[]) 该数组使用素数乘以31 并乘以计算出的哈希码中的每个元素。 考虑到上述观察由Objects.hash(Object...)为原始int值数组提供的哈希码值似乎正是该方法的实现将导致我们期望的结果整个数组的直接哈希值加上31个质数。 当该哈希码方法仅循环一个元素时传递给需要可变参数的方法的基元数组就是这种情况其计算本质上是31 * 1 directHashValueOfOverallArray 。 值得注意的是即使参考对象数组的哈希码计算得出的结果与将元素传递给接受可变参数的方法时的结果相同还是最好避免将参考对象数组传递给这样的对象。方法。 当发生这种情况时 javac编译器会提供此警告“警告对最后一个参数使用不精确参数类型的varargs方法的非varargs调用”并添加了有关解决此问题的潜在方法的这些有用的细节“为varargs调用广播到对象” “广播到Object []以进行非可变参数调用并禁止显示此警告”。 当然对于JDK 8和更高版本在将数组提供给需要可变参数的方法之前以多种其他方式处理数组是相当简单的。 我在原始帖子 及其DZone联合版本 中添加了最后一段以尝试快速解决此问题但是我已使用此帖子来更详细地表达此信息。 此处总结的经验教训可以概括为“对原始数组使用适当的重载Arrays.hashCode方法而不是使用Objects.hash(Object...) ”和“对数组数组使用Favor Arrays.hashCode(Object[]) ”。引用类型而不是使用Objects.hash(Object...) 。” 如果调用的方法“看到”的元素数量无论如何都是重要的则更通用的准则是要警惕将原始值数组传递给需要Object类型变量参数的方法并且要警惕传递引用数组指向期望可变参数的方法的对象以避免编译器警告和模棱两可的警告。 翻译自: https://www.javacodegeeks.com/2018/09/java-subtlety-with-arrays-of-primitives-and-variable-arguments.html