Object类是一切类的超类,在类继承的树形结构上,Object是所有类的根节点。所有的对象,包括数据,都继承了Object类的方法。

registerNatives

1
2
3
4
private static native void registerNatives();
static {
registerNatives();
}

getClass

1
public final native Class<?> getClass();

hashCode

1
public native int hashCode();
  1. hashCode 表示对象在 hash 表中的位置,对于同一个对象来说,多次调用,返回相同的 hashCode。
  2. 如果 Object.equal () 相等,Object.hashCode () 也必然相等。重写时也建议保证此特性。
  3. 如果 Object.equal () 相等,这并不要求 Object.hashCode () 也返回不同值。如果真出现这种情况,最好优化代码,充分利用 hash 表的性能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
// This form uses an unguarded global Park-Miller RNG,
// so it's possible for two threads to race and generate the same RNG.
// On MP system we'll have lots of RW access to a global, so the
// mechanism induces lots of coherency traffic.
value = os::random() ;
} else
if (hashCode == 1) {
// This variation has the property of being stable (idempotent)
// between STW operations. This can be useful in some of the 1-0
// synchronization schemes.
intptr_t addrBits = intptr_t(obj) >> 3 ;
value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
} else
if (hashCode == 2) {
value = 1 ; // for sensitivity testing
} else
if (hashCode == 3) {
value = ++GVars.hcSequence ;
} else
if (hashCode == 4) {
value = intptr_t(obj) ;
} else {
// Marsaglia's xor-shift scheme with thread-specific state
// This is probably the best overall implementation -- we'll
// likely make this the default in future releases.
unsigned t = Self->_hashStateX ;
t ^= (t << 11) ;
Self->_hashStateX = Self->_hashStateY ;
Self->_hashStateY = Self->_hashStateZ ;
Self->_hashStateZ = Self->_hashStateW ;
unsigned v = Self->_hashStateW ;
v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
Self->_hashStateW = v ;
value = v ;
}

value &= markOopDesc::hash_mask;
if (value == 0) value = 0xBAD ;
assert (value != markOopDesc::no_hash, "invariant") ;
TEVENT (hashCode: GENERATE) ;
return value;
}

源码中的 hashCode 其实就是 JVM 启动的一个参数,每一个分支对应一个生成策略。通过 -XX:hashCode,可以任意切换 hashCode 的生成策略。

首先解释一下入参 oop obj 就是对象的逻辑地址。所以与地址相关的生成策略有两条,在 hashCode 等于 1 或 4 的时候。

  • hashCode==1:这种方式具有幂等的性质,在 STW(stop-the-world)操作中,这种策略通常用于同步方案中。利用对象地址计算,使用不经常更新的随机数参与运算。
  • hashCode==4:与创建对象的内存位置有关,原样输出。

其他情况:

  • hashCode==0:简单地返回随机数,与对象的内存地址没有联系。然而根据随机数生成并全局地读写在多处理器下并不占优势。
  • hashCode==2:始终返回完全相同的标识,即 hashCode=1。这可用于测试依赖对象标识的代码。
  • hashcode==3:从零开始计算哈希代码值。它看起来不是线程安全的,因此多个线程可以生成具有相同哈希代码的对象。
  • hashCode>=5(默认):在 jdk1.8 中,这是默认的 hashCode 生成算法,支持多线程生成。使用了 Marsaglia 的 xor-shift 算法产生伪随机数。

xor-shift 算法

1
2
3
4
5
6
7
8
9
10
11
uint32_t xor128(void) {
static uint32_t x = 123456789;
static uint32_t y = 362436069;
static uint32_t z = 521288629;
static uint32_t w = 88675123;
uint32_t t;

t = x ^ (x <<11);
x = y; y = z; z = w;
return w = w ^ (w>> 19) ^ (t ^ (t>> 8));
}

String重写hashCode

1
2
3
4
5
6
7
8
9
10
11
12
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;

for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}

相同的字符串调用hashCode()方法,得到的值是一样的,与内存地址、进程、及其无关。

为什么计算时选择31

  1. 31 是个奇质数,不大不小,一般质数非常适合 hash 计算。
    偶数相当于移位运算,容易溢出,数据信息丢失。
    如果太小,则产生的哈希值区间小;太大则容易溢出,数据信息丢失。
  2. 31 * i == (i << 5) - i。非常易于维护,将移位代替乘除,会有性能的提升,并且 JVM 执行时能够自动优化成这个样子。
  3. 通过实验计算,选用 31 后出现 hash 冲突的概率相比于其他数字要小。

equals

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

每当重写hashCode方法的时候,通常都需要重写该方法,以便维护hashCode方法的常规约定,该方法申明相等的对象必须具有相同的hashCode。

clone

1
protected native Object clone() throws CloneNotSupportedException;

toString

1
2
3
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

notify

1
public final native void notify();

notifyAll

1
public final native void notifyAll();

wait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public final native void wait(long timeout) throws InterruptedException;

public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}

if (nanos > 0) {
timeout++;
}

wait(timeout);
}

public final void wait() throws InterruptedException {
wait(0);
}

finalize

1
protected void finalize() throws Throwable { }