java-beginner.com ブログ

プログラミングを学習するブログ(Javaをメインに)

long型とhashCode

投稿日:

最終更新日:2016年07月22日

アイキャッチ

こんにちは。「Javaを復習する初心者」です。

Object#hashCodeメソッドはint型変数を返却するメソッドです。フィールドに他のプリミティブ型変数がある場合、Eclipseはどのようなコードを自動生成するのかを試しました。その中で、個人的にlong型について興味深かったので、そのことを書きます。EclipseではhashCodeメソッドをフィールドから自動生成してくれます。前回はint型変数2つで試しました。今回はその他のプリミティブ型について調べてみました。

プリミティブ型とhashCode

プリミティブ型は以下があります。

  • boolean
  • char
  • byte
  • short
  • int
  • long
  • float
  • double

以上の型の変数をフィールドに一つずつ持つクラスを作り、hashCodeメソッドを自動生成してみました。以下がソースです。

ソースコード

package objectTest;

public class HelloHashCodePrimitive {

    public boolean booleanValue;
    public char    charValue;
    public byte    byteValue;
    public short   shortValue;
    public int     intValue;
    public long    longValue;
    public float   floatValue;
    public double  doubleValue;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (booleanValue ? 1231 : 1237);
        result = prime * result + byteValue;
        result = prime * result + charValue;
        long temp;
        temp = Double.doubleToLongBits(doubleValue);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        result = prime * result + Float.floatToIntBits(floatValue);
        result = prime * result + intValue;
        result = prime * result + (int) (longValue ^ (longValue >>> 32));
        result = prime * result + shortValue;
        return result;
    }

}

boolean型、fouat型、double型はそれぞれ工夫があります。booleanValueは3項演算子で異なる値に変換してます。FloatはfloatToIntBitsというメソッドを使うようです。API仕様書を見たのですが、とにかくint型が返却されるようです。Double型も最初に似たようなことをしてます。そこで気になったのがlong型でも使っている「^」と「>>>」です。

long型での処理

「longValue ^ (longValue >>> 32)」の箇所が何となく気になりました。「^」はビット演算子でXOR演算です。「>>>」はビット演算子でゼロ埋め右シフトのようですが、long型変数をシフトしているので桁が減るだけのようです。long型に「1」が格納されている場合、「longValue >>> 32」の一桁目は「0」になり「^」の結果は「1」になります。そのため、2進数「1」と「100000000000000000000000000000000」は同じ結果になります。

ということを実験してみました。以下はソースと実行結果です。

ソース

package objectTest;

public class HelloHashCodePrimitiveLongTest {

    public static void main(String[] args) {

        long longValue = 1L;


        int hashCode = (int) (longValue ^ (longValue >>> 32));

        System.out.println(String.format("%64s", Long.toBinaryString(longValue)).replace(" ", "_"));
        System.out.println(String.format("%64s", Long.toBinaryString(longValue >>> 32)).replace(" ", "_"));

        System.out.println(String.format("%64s", Long.toBinaryString(hashCode)).replace(" ", "_"));

        System.out.println();
        longValue = 4294967296L;

        hashCode = (int) (longValue ^ (longValue >>> 32));

        System.out.println(String.format("%64s", Long.toBinaryString(longValue)).replace(" ", "_"));
        System.out.println(String.format("%64s", Long.toBinaryString(longValue >>> 32)).replace(" ", "_"));

        System.out.println(String.format("%64s", Long.toBinaryString(hashCode)).replace(" ", "_"));

    }

}

結果

_______________________________________________________________1
_______________________________________________________________0
_______________________________________________________________1

_______________________________100000000000000000000000000000000
_______________________________________________________________1
_______________________________________________________________1

64桁出力で空白は「_」埋めで出力しました。HTMLは連続する半角空白が1個分になってしまうからです。

個人的にはこのhashCodeは不思議な重複をするなあという感想です。「2」と重複するのは何かというと「4294967296L * 2」です。