public static long hash64(byte[] data) {
		int len = data.length;
		if (len <= 32) {
			if (len <= 16) {
				return hashLen0to16(data);
			} else {
				return hashLen17to32(data);
			}
		} else if (len <= 64) {
			return hashLen33to64(data);
		}

		// For strings over 64 bytes we hash the end first, and then as we
		// loop we keep 56 bytes of state: v, w, x, y, and z.
		long x = fetch64(data, len - 40);
		long y = fetch64(data, len - 16) + fetch64(data, len - 56);
		long z = hashLen16(fetch64(data, len - 48) + len, fetch64(data, len - 24));
		Number128 v = weakHashLen32WithSeeds(data, len - 64, len, z);
		Number128 w = weakHashLen32WithSeeds(data, len - 32, y + k1, x);
		x = x * k1 + fetch64(data, 0);

		// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
		len = (len - 1) & ~63;
		int pos = 0;
		do {
			x = rotate64(x + y + v.getLowValue() + fetch64(data, pos + 8), 37) * k1;
			y = rotate64(y + v.getHighValue() + fetch64(data, pos + 48), 42) * k1;
			x ^= w.getHighValue();
			y += v.getLowValue() + fetch64(data, pos + 40);
			z = rotate64(z + w.getLowValue(), 33) * k1;
			v = weakHashLen32WithSeeds(data, pos, v.getHighValue() * k1, x + w.getLowValue());
			w = weakHashLen32WithSeeds(data, pos + 32, z + w.getHighValue(), y + fetch64(data, pos + 16));
			// swap z,x value
			long swapValue = x;
			x = z;
			z = swapValue;
			pos += 64;
			len -= 64;
		} while (len != 0);
		return hashLen16(hashLen16(v.getLowValue(), w.getLowValue()) + shiftMix(y) * k1 + z,
				hashLen16(v.getHighValue(), w.getHighValue()) + x);
	}
@Test
	public void hash64Test() {
		long hv = CityHash.hash64(StrUtil.utf8Bytes("你"));
		assertEquals(-4296898700418225525L, hv);

		hv = CityHash.hash64(StrUtil.utf8Bytes("你好"));
		assertEquals(-4294276205456761303L, hv);

		hv = CityHash.hash64(StrUtil.utf8Bytes("见到你很高兴"));
		assertEquals(272351505337503793L, hv);
		hv = CityHash.hash64(StrUtil.utf8Bytes("我们将通过生成一个大的文件的方式来检验各种方法的执行效率因为这种方式在结束的时候需要执行文件"));
		assertEquals(-8234735310919228703L, hv);
	}