Java的精妙之处,包括基元和变量参数数组

在我最近的博客文章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.hashCode(int [])的结果与在同一原始int值数组上调用Objects.hash(Object…)的结果不同。

对原始反馈评论的一个答复准确地指出,不能保证在不同JVM上生成的哈希码是相同的。 实际上, Object.hashCode()方法的Javadoc注释指出(我强调了 ):

  • 只要在Java应用程序执行期间同一对象上多次调用它,hashCode方法就必须一致地返回相同的整数,前提是不修改该对象的equals比较中使用的信息。 从一个应用程序的执行到同一应用程序的另一执行,此整数不必保持一致。
  • 如果根据equals(Object)方法,两个对象相等,则在两个对象中的每个对象上调用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;@2752f6e2
==> Array int[] - Variable Arguments (10 elements): class [I - [I@1cd072a9Integer[]
==> Ellipsis Object... - Variable Arguments (10 elements): class [Ljava.lang.Integer; - [Ljava.lang.Integer;@7c75222b
==> Array 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/345423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【渝粤题库】陕西师范大学163201 旅游科学引论作业(专升本)

《旅游科学引论》作业 一、简答题 1、旅游是什么&#xff1f; 2、旅游学的研究对象是什么&#xff1f; 3、旅游能干什么&#xff1f; 4、什么是旅游学&#xff1f; 5、旅游的本质是什么&#xff1f; 6、旅游学的学科性质是什么&#xff1f; 7、旅游学的学科如何构成&#xff1f…

【渝粤题库】陕西师范大学180103市场营销学Ⅰ作业(高起专)

《市场营销学I》作业 一、单项选择题 1、人的需求是无限的&#xff0c;但是有限的&#xff08; &#xff09;限制了人们的大部分欲求。 A&#xff0e;场所 B&#xff0e;商品交换关系 C&#xff0e;人口 D&#xff0e;购买力 2、市场营销的核心是&#xff08; &#xff09;。 …

MATLAB | 解决打开延迟的情况

问题 最近打开matlab&#xff0c;一直没有反应&#xff0c;大概几分钟后&#xff0c;才开始有反应。 网上关于matlab启动出现延迟的方法有很多种解决方法。但都是针对破解版的&#xff0c;而装正版matlab2020b&#xff0c;缺少license文件。对于此&#xff0c;我们尝试用另外一…

【渝粤题库】陕西师范大学200751 《操作系统》作业

《操作系统》作业 一&#xff0e;填空题。 1.加在计算机硬件上的第一层软件为 它是微机以至任何一台计算机必须配置的系统软件。 2.操作系统设计时追求的目标中&#xff0c;其有效性是指 。 3.批(包括多道和单道)处理系统的最大缺点是 &#xff0c;从而使得用户调试程序的周期…

50 个具有挑战性的概率问题 [01/50]:袜子抽屉

一、说明 我最近对与概率有关的问题产生了兴趣。我偶然读到了弗雷德里克莫斯特勒&#xff08;Frederick Mosteller&#xff09;的《概率论中的五十个具有挑战性的问题与解决方案》&#xff08;Fifty Challenge Problems in Probability with Solutions&#xff09;一书。我认为…

matlab中数值的取整、四舍五入、文本输出

一、取整函数 Matlab取整函数有: fix, floor, ceil, round四种&#xff0c;具体使用方法如下&#xff1a; (1) fix 朝零方向取整 如 fix(-1.3)-1 fix(1.3)1; (2) floor 朝负无穷方向取整&#xff08;不超过x 的最大整数.&#xff08;高斯取整&#xff09;&#xff09; …

【渝粤题库】陕西师范大学201341 刑事诉讼法学作业

《刑事诉讼法》作业 一、单项选择题 1&#xff0e;公诉案件中的犯罪嫌疑人有权委托辨护人的时间是下列选项中的哪一个&#xff1f;&#xff08; &#xff09; A 自侦查机关立案之日起 B 自被采取强制措施之日起 C 自案件移送起诉之日起 D 自案件做出起诉决定之日起 2&#xff0…

制作程序化装饰花纹图案_装饰图案

制作程序化装饰花纹图案装饰图案 我不经常使用的一种设计模式是Decorator 。 我不确定为什么这种模式不受欢迎&#xff0c;因为它很方便。 装饰器模式允许以受控方式向对象添加功能。 即使在使用静态类型的语言时&#xff0c;也可以在运行时运行&#xff01; 装饰器模式是子类的…

[渝粤题库]西北工业大学电力系统自动装置

电力系统自动装置 一. 单选题 &#xff08;共21题,共42分&#xff09; 发电机调速系统的失灵区&#xff08; &#xff09;。 &#xff08;2分&#xff09; A.越大越好 B.越小越好 C.要合适同步发电机无功调节特性特性下倾&#xff0c;对应的调差系数&#xff08; &#xff09;…

game,match,competition,contest区别

【1】game&#xff1a; 指决定胜负的比赛&#xff0c;游戏&#xff0c;通常有一定的规则&#xff0c;参加者必须遵守&#xff0c;且多以个人对抗或集体对抗形式根据一定的规则进行的比赛。 【2】match&#xff1a; 多指重要的&#xff0c;参加队数较多的大型体育运动项目比赛&…

[渝粤题库]西北工业大学经济数学(上) (1)

经济数学&#xff08;上&#xff09; 1.&#xff08; &#xff09;. C. 答案:C 2.极限等于&#xff08; &#xff09;. A.0 答案:A 3.已知&#xff0c;当&#xff08; &#xff09;时&#xff0c;为无穷小量. A. 答案:A 4.&#xff08; &#xff09;. C. 答案:C 5.&#xff08…

[渝粤题库]西北工业大学高等数学(上)

高等数学&#xff08;上&#xff09; 当时&#xff0c;与比较是&#xff08; 非等价的同阶无穷小量 &#xff09;. 当时&#xff0c;与等价的无穷小量是&#xff08; &#xff09;. 10、当x→0时&#xff0c;下面无穷小量中与x等价的无穷小量为&#xff08; sin x &#xff09;…

assure, ensure, insure, guarantee的区别

assure, ensure, insure, guarantee都含有一定的"保证"之意 assure 表示向某人保证某事一定会发生(内含有让某人放心之意&#xff0c;以消除疑虑) assure sb. of sth /assure sb. that… He assured us of his ability to solve the problem&#xff0e;他向我们保…

6个您需要了解的日志管理工具(以及如何使用它们)

如果没有正确的工具来汇总和解析日志数据&#xff0c;则几乎不可能找到并了解您正在寻找的信息。 日志有无穷无尽的用途&#xff0c;因为日志本身是无止境的。 应用程序日志&#xff0c;安全日志&#xff0c;BI日志&#xff0c; 林肯日志 &#xff08;好吧&#xff0c;也许不是…

【渝粤题库】国家开放大学2021春2444酒店管理概论答案

试卷代号&#xff1a;2444 2 0 2 1年春季学期期末统一考试 酒店管理概论试题答案及评分标准 &#xff08;供参考&#xff09; 2021年7月 一、单项选择题&#xff08;在备选答案中&#xff0c;有1个正确答案&#xff0c;请将正确答案的字母填在括号内&#xff0c;每小题2分&…

学术英语:关于such as, for example, etc., and so on, i.e., 和e.g.的使用

英语写作里会遇到需要列举的时候&#xff0c;常用的方式和使用的表达有such as&#xff0c;for example&#xff0c;etc.等等。在这里&#xff0c;我想介绍的是如何正确使用这些表达。 such as… 和 for example… 都表示“例如”的意思&#xff0c;即提示下面将会举例子&…

【渝粤题库】国家开放大学2021春2608中级财务会计(二)题目

试卷代号&#xff1a;2608 2021年春季学期期末统一考试 中级财务会计&#xff08;二&#xff09; 试题 2021年7月 一、单项选择题&#xff08;从下列每小题的四个选项中选择一个正确的&#xff0c;将其序号填入题后的括号里。每小题3分.共30分&#xff09; 1.商业承兑汇票到期无…

【渝粤题库】国家开放大学2021春2726畜禽生产概论题目

试卷代号&#xff1a;2726 2021年春季学期期末统一考试 畜禽生产概论 试题 2021年7月 一、单项选择题&#xff08;将你认为正确答案前的字母填在括号内。每小题3分&#xff0c;共45分&#xff09; 1.仔猪生后( )日龄前主要靠母乳供给营养。 A.20 B.30 C.40 D.50 2.初生仔猪需要…

英文邮件常用句子(工作场景)

「开头打招呼」&#xff1a;一般用hello/hi就行了&#xff0c;dear比较正式&#xff0c;显得不亲近。 Dear all 「自我介绍」 My name is xxx and I’m the 职位 of 公司. 「表明目的」 I am writing to confirm/enquire/inform you … 我写邮件是要确认/询问/通知你 「表示对来…

【渝粤题库】国家开放大学2021春2772家畜环境卫生与设施题目

试卷代号&#xff1a;2772 2021年春季学期期末统一考试 家畜环境卫生与设施 试题 2021年7月 一、单项选择题&#xff08;每小题3分&#xff0c;共30分&#xff09; 1.环境温度适宜时&#xff0c;机体的蒸发散热量约占总散热量的( )。 A.17% B.20% C.25% D.30% 2.机体散热使得环…