Object
类是所有类的超类。
所有对象(包括数组)都实现这个类的方法。
因此我们很有必要了解一下它。
equals()
Object
的 equals()
是直接比较两个对象的引用是否相同。
如果需要判断对象的属性值是否相等,需要覆盖这个方法。
除了 String
的 equals()
很常见以外,其实还有很多地方,都可能会用到 equals()
,例如,在集合类中的 contains(Object)
、 remove(Object)
都用到了: (o==null ? e==null : o.equals(e))
。
覆盖 equals()
需要注意的是,需要满足以下条件:
- 自反性:
x.equals(x)
返回true
; - 对称性:若
x.equals(y)
为true
,则y.equals(x)
亦为true
; - 传递性:若
x.equals(y)
为true
且y.equals(z)
也为true
,则x.equals(z)
亦为true
; - 一致性:
x.equals(y)
的第一次调用为true
,那么x.equals(y)
的第 2 次、第 3 次、第 n 次调用也均为true
,前提条件是没有修改 x 也没有修改 y; - 对于非空引用 x ,
x.equals(null)
返回为false
。
常见的写法:
1 | public boolean equals(Object obj) { |
hashCode()
有一些基于 Hash 算法的数据结构(例如:HashMap
、HashSet
)需要用到这个方法。
散列值并没有什么实际含义,只是用来标记对象的。
因为不同对象的散列值一般不同(但并不是绝对的)。
如果覆盖了 equals()
,那么一般也要覆盖 hashCode()
,以便于用户可以正确地将对象插入到散列表。
并且, hashCode()
返回的值应该能够尽量地离散分布。
toString()
Object
的 toString()
直接输出对象的类名和散列码。
没有什么实际用处,一般都需要覆盖。
当我们调用 System.out.println(x)
的时候,实际上相当于 System.out.println(x.toString())
。
clone()
关于对象的克隆,有浅克隆和深克隆之分。
浅克隆,只会克隆一层,如果被克隆的对象的属性是一个引用,那么这个引用还是指向原来的对象,如果这个属性,是不可变的(例如:String
、Integer
、Long
),那么不会与什么问题,否则,这样的共享,往往是会带来问题的,需要注意。
Object
类的 clone()
方法属于浅克隆,还是 protected
方法。
实现深克隆的类,需要:
- 实现
Cloneable
接口(建议需要浅克隆时,也声明这个接口)。 - 覆盖
Object
的clone()
方法,并使用public
修饰。 - 克隆该对象所有可变的属性。
wait()
调用 wait()
方法,会使当前线程立即释放在此对象上的锁,从而进入等待状态,直至被 notify()
方法或 notifyAll()
方法唤醒。
需要注意的是,wait()
必须在同步方法或代码块中调用。
notify() 和 notifyAll()
notify()
是唤醒在此对象监视器上等待的单个线程,但仅仅只是起到一个通知的作用,不释放锁,也不获取锁。如果所有线程都在此对象上等待,会随机选择唤醒其中一个线程。
notifyAll()
则是唤醒在此对象监视器上等待的所有线程。
同样的,notify()
和 notifyAll()
也必须在同步方法或代码块中调用。
finalize()
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用 finalize()
方法。
这个方法的设计初衷应该是,想让开发者能够在垃圾回收之前做一些善后的工作。
然而,事实上,我们无法确定这个方法究竟什么时候会被调用。因此,不可靠,不要使用它。
Objects类
另外,JDK 1.7 还新增了 java.util.Objects
类,它提供了对象检查和处理 hash
等操作的静态方法,例如:
- equals(Object a, Object b)
- deepEquals(Object a, Object b)
- isNull(Object obj)
- nonNull(Object obj)
- requireNonNull(T obj, String message)
- hashCode(Object o)
- hash(Object… values)
附: Object
类的源代码
1 | package java.lang; |