0%

Java Object

阅读Java8的Object源码,写下了自己的一些笔记

Object类是所有类的父类,也是Java虚拟机加载的第一个类

方法

Object类中的方法有

  • registerNatives
  • getClass
  • hashCode
  • equals
  • clone
  • toString
  • notify
  • notifyAll
  • wait
  • finalize

registerNatives

调用该方法注册本地方法,调用C函数实现Java方法

getClass

是一个本地方法,返回类名

如果是匿名内部类的话,不输出任何类名

hashCode

多次调用hashCode方法要返回一致的hashCode

设计一个HashCode算法

  • 把某个非 0 的常数值,比如 17,保存在一个名为 result 的 int 类型的变量中。
  • 对于对象中的每个域,做如下操作:
    • 为该域计算 int 类型的哈希值 c :
      • 如果该域是 boolean 类型,则计算 (f?1:0)
      • 如果该域是 byte、char、short 或者 int 类型,则计算 (int)f
      • 如果该域是 long 类型,则计算 (int)(f^(f>>>32))
      • 如果该域是 float 类型,则计算 Float.floatToIntBits(f)
      • 如果该域是 double 类型,则计算 Double.doubleToLongBits(f),然后重复第三个步骤。
      • 如果该域是一个对象引用,并且该类的 equals 方法通过递归调用 equals 方法来比较这个域,同样为这个域递归的调用 hashCode,如果这个域为 null,则返回0。
      • 如果该域是数组,则要把每一个元素当作单独的域来处理,递归的运用上述规则,如果数组域中的每个元素都很重要,那么可以使用 Arrays.hashCode 方法。
  • 按照公式 result = 31 * result + c,把上面步骤 2.1 中计算得到的散列码 c 合并到 result 中。

返回 result

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

String类重写的hashCode如上

为什么使用31?

  • 31=1<<5-1,容易计算
  • 31是质数

equals

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

默认是比较对象的引用

重写equals要重写hashCode

契约:

  • equals相同hashCode也相同
  • hashCode相同equals可以不同

clone

先判断是否实现了Cloneable接口,再实现cloone方法
否则会抛出CloneNotSupportedException

clone()默认是浅拷贝

toString

默认返回类名+@+内存地址经过hash算法得出的16进制数

可以重写

notify

多线程中,用于唤醒一个线程

notifyAll

多线程中,用于唤醒所有线程

wait

多个重载,等待一段时间,如果为0,永久等待

finfnalize

几乎不用,在GC时会调用,且只调用一次,但不保证一定执行,可以在方法中与GC Roots相连避免被回收

参考资料