jdk源码每日一读 (一) java.lang.Object
jdk源码每日一读 (一) java.lang.object
1. 类说明
object是java继承体系的根,是每一个类的基类,所有的类都实现了object类的所有方法。
2.重要方法
public final native class<?> getclass() public native int hashcode(); public boolean equals(object obj); protected native object clone() throws clonenotsupportedexception; public string tostring(); public final native void notify(); public final native void notifyall(); public final native void wait(long timeout) throws interruptedexception; public final void wait(long timeout, int nanos) throws interruptedexception; public final void wait() throws interruptedexception protected void finalize() throws throwable;
3. 分析
-
getclass方法
getclass方法的返回值是class对象,它返回的是对象消除静态类型的类型,也就是说他返回的是对象的实际类型,比如说下面这个例子
public class test { public static void main(string[] args) { a a=new b(); system.out.println(a.getclass()); } } class a{ } class b extends a{ }
b是a的子类,虽然a声明的类型是a,但是getclass方法返回的类型是b
-
hashcode方法
该方法返回的是一个整形的hash码,一般这个方法用于利用到散列的类,比如说hashmap等,支持这个方法是为了提高hash表的性能。源码中强调了,如果两个类使用equals方法比较相等,那么hashcode的返回值一定相同,但是如果使用equals方法比较不同,不对hashcode的返回值是否相等做要求,但是不同对象的hashcode不相同能够提高hash表的性能。
在同一个应用中,每次调用同一个对象的hashcode方法,返回的整数一定相等。
hashcode是一个本地方法,他的返回值与对象的地址有关。
-
equals方法
比较两个对象是否相等,在object的实现中,直接使用==比较两个对象是否相等,也就是说比较的是两个对象的地址是否相等,如果有特殊的要求,如字符串的内容相等则可以认为两个字符串是相等的,那么应该重写equal方法,当然也不要忘记重写hashcode方法。
public boolean equals(object obj) { return (this == obj); }
重写equal方法要满足下列要求
-
自反性:对于任何非空引用值
x
,x.equals(x)
都应返回true
。 -
对称性:对于任何非空引用值
x
和y
,当且仅当y.equals(x)
返回true
时,x.equals(y)
才应返回true
。 -
传递性:对于任何非空引用值
x
、y
和z
,如果x.equals(y)
返回true
,并且y.equals(z)
返回true
,那么x.equals(z)
应返回true
。 -
一致性:对于任何非空引用值
x
和y
,多次调用x.equals(y)
始终返回true
或始终返回false
,前提是对象上equals
比较中所用的信息没有被修改。 - 对于任何非空引用值
x
,x.equals(null)
都应返回false
。
-
自反性:对于任何非空引用值
-
clone方法
返回该对象的副本,对于一般类,必须实现cloneable接口,该接口是一个标记接口,里面没有内容。
public interface cloneable { }
-
tostring方法
返回一个表示该类信息的字符串,需要子类去重写tostring方法,默认实现如下: 类名+@+哈希码的16进制字符串
public string tostring() { return getclass().getname() + "@" + integer.tohexstring(hashcode());
-
notify方法
随机唤醒在此对象监视器上等待的其中一个线程。
-
notifyall方法
唤醒在此对象监视器上等待的所有线程
-
wait方法
调用wait系列方法,当前线程将会等待,并放弃该对象的监视器的所有权,调用该方法之前当前线程必须拥有该对象的监视器的所有权。
-
finalize方法
当垃圾回收器确定不存在对该对象的更多引用时(该对象可以被回收),由对象的垃圾回收器调用此方法。子类可以重写该方法,使得该对象避免被回收,具体的做法是让该对象再次存在引用,但是注意该方法只能被调用一次。
4. 问题
-
为什么重写equals方法要重写hashcode方法
个人理解:hashcode方法在被设计的时候就是为了提高与hash相关的数据结构的性能,具体是如何提高的呢?以hashmap为例,当需要查找某个元素的时候,hashmap判断某个key是否相等的时候,为了速度,首先是判断的hashcode是否相等,然后通过equals方法判断是否相等。所以如果重写了equals而没有重写hashcode就会造成不一致性,也就是说通过equals方法判断两个对象是相等的,而hashcode未重写的时候默认返回的值与对象的地址有关,这样hashcode势必就不相等了。所以为了保证比较时的一致性在重写equals方法的时候一定要重写hashcode方法,这一点在hashcode方法的源码注释里也说明了。
-
clone方法在什么情况下使用
个人理解:clone用来复制一个对象,在java中创建一个对象有很多方式,比如说使用new关键字,反射以及clone方法。对比一下new和clone的区别,new一个对象的时候,首先会去检查该对象的class文件是否加载进入方法区,如果没有则先去加载class文件,然后分配一块空间给对象,之后再进行一系列的初始化,这样就在堆中得到了一个对象,而clone方法则是在根据一个对象中复制另一个新的对象。在有的场景中,我们可能需要一系列相同的对象,但是这些对象通过new创建的成本却很高,这时就可以调用clone方法,这在设计模式中的原型设计模式中得到了应用。同时有的时候我么也有复制对象的场景,但是通过引用赋值的方式,只能复制引用,不能复制堆中的对象。
clone还有深拷贝和浅拷贝的区别。深拷贝指得是对象本身以及对象包含的引用指向的堆中对象都进行拷贝,浅拷贝则是引用进行了复制但没有真正拷贝引用所指向的对象。