日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

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

發(fā)布時間:2023/12/3 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java的精妙之处,包括基元和变量参数数组 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在我最近的博客文章Arrays.hashCode()與 DZone聯(lián)合版本的評論中提出了一個有趣的問題。 Objects.hash() “。 該評論的作者建立了一些示例,這些示例與我的博客文章中使用的示例相似,并且顯示出與我看到的結(jié)果不同的結(jié)果。 感謝評論作者抽出寶貴的時間來發(fā)表這篇文章,因為它帶來了Java的細(xì)微差別,我認(rèn)為這很值得寫博客。

評論作者顯示了以下有效的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)));

該評論的作者提到,對于所有四個語句,運(yùn)行剛顯示的代碼的結(jié)果都完全相同。 這與我的示例不同,在示例中,在原始int值數(shù)組上調(diào)用Arrays.hashCode(int [])的結(jié)果與在同一原始int值數(shù)組上調(diào)用Objects.hash(Object…)的結(jié)果不同。

對原始反饋評論的一個答復(fù)準(zhǔn)確地指出,不能保證在不同JVM上生成的哈希碼是相同的。 實(shí)際上, Object.hashCode()方法的Javadoc注釋指出(我強(qiáng)調(diào)了 ):

  • 只要在Java應(yīng)用程序執(zhí)行期間在同一對象上多次調(diào)用它,hashCode方法就必須一致地返回相同的整數(shù),前提是不修改該對象的equals比較中使用的信息。 從一個應(yīng)用程序的執(zhí)行到同一應(yīng)用程序的另一執(zhí)行,此整數(shù)不必保持一致。
  • 如果根據(jù)equals(Object)方法,兩個對象相等,則在兩個對象中的每個對象上調(diào)用hashCode方法必須產(chǎn)生相同的整數(shù)結(jié)果。

陳述了所有這些內(nèi)容之后,為整數(shù)計算的哈希碼通常在每次運(yùn)行之間都是一致的。 原始評論者示例的輸出都具有完全相同的值也很有趣。 盡管我可能不希望這些值與示例的值相匹配,但是令人驚訝的是,評論者提供的所有示例都具有相同的答案。

反饋?zhàn)⑨屩刑峁┑氖纠c我的示例之間的區(qū)別在于注釋者的示例如何為原始int值數(shù)組調(diào)用Objects.hash(Object...)與我的示例如何調(diào)用Objects.hash(Object...)用于原始int值的數(shù)組。 在我的示例中,我將相同的本地數(shù)組傳遞給所有方法調(diào)用。 該注釋者的示例將原始int值的顯式數(shù)組傳遞給Arrays.hashCode(int[]) ,但將各個int元素傳遞給Objects.hash(Object...)而不是將數(shù)組傳遞給后一個方法。 當(dāng)我向注釋者的示例集中添加另一個示例,該示例確實(shí)將原始int值數(shù)組傳遞給Objects.hash(Object...)方法時,我得到的生成的哈希碼與所有其他哈希碼不同。 接下來顯示該增強(qiáng)的代碼。

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));

運(yùn)行注釋器提供的代碼的經(jīng)過調(diào)整和增強(qiáng)的版本會導(dǎo)致輸出(帶有我添加的示例突出顯示):

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

將輸出與生成它的代碼進(jìn)行比較,可以看出,當(dāng)將int值數(shù)組的元素傳遞給Arrays.hashCode(int[]) ,它與Objects.hash(Object...)生成相同的哈希碼值Objects.hash(Object...)方法作為單個元素。 但是,我們還可以看到,當(dāng)完整地傳遞原始int值的數(shù)組(作為單個數(shù)組而不是作為數(shù)組的單個元素)時, Objects.hash(Object...)方法生成了完全不同的哈希碼。 我添加的其他兩個示例(突出顯示)是通過直接在數(shù)組上調(diào)用.hashCode()或通過Objects.hashCode獲得等效結(jié)果來顯示原始int值數(shù)組上的“直接”哈希碼。 (對象) 。 [這并非巧合, Objects.hash(Object...)為原始int值數(shù)組生成的哈希碼比為原始int值數(shù)組生成的“直接”哈希碼正好大31。 ]

所有這些都指向這里的真正問題:通常最好不要將原語數(shù)組傳遞給接受可變參數(shù) (通告省略號 )的方法。 SonarSource規(guī)則瀏覽器 ( Java )在RSPEC-3878中提供了有關(guān)此內(nèi)容的更多詳細(xì)信息。 與規(guī)則描述特別相關(guān)的是與歧義有關(guān)的問題:“數(shù)組應(yīng)該是一個對象還是對象的集合?”

剛剛提出的問題的答案是,當(dāng)將原始int值數(shù)組傳遞給接受方法Objects.hash(Object...)的變量參數(shù)時, 整個數(shù)組將被視為單個 Object 。 相反,當(dāng)將引用對象的數(shù)組(例如Integer )傳遞給相同的方法時,它將其視為與數(shù)組中的元素傳遞給它的對象數(shù)量相同。 下一個代碼清單和相關(guān)輸出證明了這一點(diǎn)。

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

剛剛顯示的示例代碼和相關(guān)的輸出表明,期望變量參數(shù)的方法將傳遞給它的原始值數(shù)組視為單個元素數(shù)組 。 另一方面,相同的方法將傳遞給具有參考對象類型的數(shù)組的數(shù)組視為具有相同元素數(shù)的數(shù)組。

考慮到這一點(diǎn),請返回哈希碼生成示例,由Objects.hash(Object...)為原始int值數(shù)組生成的哈希碼與由Arrays.hashCode(int[])生成的哈希碼不同。 類似地,我們現(xiàn)在可以解釋為什么對象引用數(shù)組導(dǎo)致相同的哈希碼,而不管調(diào)用了哪種方法。

前面我提到過,由Objects.hash(Object)生成的哈希碼比整個數(shù)組的“直接”哈希碼高31并非巧合。 這并不奇怪,因為Objects.hash(Object...)的OpenJDK實(shí)現(xiàn)將Arrays.hashCode(Object[]) Objects.hash(Object...)委托給Arrays.hashCode(Object[]) ,該數(shù)組使用素數(shù)乘以31 ,并乘以計算出的哈希碼中的每個元素。 考慮到上述觀察,由Objects.hash(Object...)為原始int值數(shù)組提供的哈希碼值似乎正是該方法的實(shí)現(xiàn)將導(dǎo)致我們期望的結(jié)果:整個數(shù)組的直接哈希值加上31個質(zhì)數(shù)。 當(dāng)該哈希碼方法僅循環(huán)一個元素時(傳遞給需要可變參數(shù)的方法的基元數(shù)組就是這種情況),其計算本質(zhì)上是31 * 1 + <directHashValueOfOverallArray> 。

值得注意的是,即使參考對象數(shù)組的哈希碼計算得出的結(jié)果與將元素傳遞給接受可變參數(shù)的方法時的結(jié)果相同,還是最好避免將參考對象數(shù)組傳遞給這樣的對象。方法。 當(dāng)發(fā)生這種情況時, javac編譯器會提供此警告:“警告:對最后一個參數(shù)使用不精確參數(shù)類型的varargs方法的非varargs調(diào)用”,并添加了有關(guān)解決此問題的潛在方法的這些有用的細(xì)節(jié):“為varargs調(diào)用廣播到對象” “廣播到Object []以進(jìn)行非可變參數(shù)調(diào)用并禁止顯示此警告”。 當(dāng)然,對于JDK 8和更高版本,在將數(shù)組提供給需要可變參數(shù)的方法之前,以多種其他方式處理數(shù)組是相當(dāng)簡單的。

我在原始帖子 (及其DZone聯(lián)合版本 )中添加了最后一段,以嘗試快速解決此問題,但是我已使用此帖子來更詳細(xì)地表達(dá)此信息。 此處總結(jié)的經(jīng)驗教訓(xùn)可以概括為“對原始數(shù)組使用適當(dāng)?shù)闹剌dArrays.hashCode方法,而不是使用Objects.hash(Object...) ”和“對數(shù)組數(shù)組使用Favor Arrays.hashCode(Object[]) ”。引用類型,而不是使用Objects.hash(Object...) 。” 如果調(diào)用的方法“看到”的元素數(shù)量無論如何都是重要的,則更通用的準(zhǔn)則是要警惕將原始值數(shù)組傳遞給需要Object類型變量參數(shù)的方法,并且要警惕傳遞引用數(shù)組指向期望可變參數(shù)的方法的對象,以避免編譯器警告和模棱兩可的警告。

翻譯自: https://www.javacodegeeks.com/2018/09/java-subtlety-with-arrays-of-primitives-and-variable-arguments.html

總結(jié)

以上是生活随笔為你收集整理的Java的精妙之处,包括基元和变量参数数组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。