阅读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 方法。
- 为该域计算 int 类型的哈希值 c :
- 按照公式 result = 31 * result + c,把上面步骤 2.1 中计算得到的散列码 c 合并到 result 中。
返回 result
1 | public int hashCode() { |
String类重写的hashCode如上
为什么使用31?
- 31=1<<5-1,容易计算
- 31是质数
equals
1 | public boolean equals(Object obj) { |
默认是比较对象的引用
重写equals要重写hashCode
契约:
- equals相同hashCode也相同
- hashCode相同equals可以不同
clone
先判断是否实现了Cloneable接口,再实现cloone方法
否则会抛出CloneNotSupportedException
clone()默认是浅拷贝
toString
默认返回类名+@+内存地址经过hash算法得出的16进制数
可以重写
notify
多线程中,用于唤醒一个线程
notifyAll
多线程中,用于唤醒所有线程
wait
多个重载,等待一段时间,如果为0,永久等待
finfnalize
几乎不用,在GC时会调用,且只调用一次,但不保证一定执行,可以在方法中与GC Roots相连避免被回收
参考资料
- 解析hashCode
- JDK1.8源码