こんにちは。「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」です。