JDK8源码之Object(一)

先来看一下oracle官方对Object的解释:

* Class {@code Object} is the root of the class hierarchy.
* Every class has {@code Object} as a superclass. All objects,
* including arrays, implement the methods of this class.

 翻译过来就是说:Object类是(java里)类层次结构的跟。任何一个类都有一个Object超类,所有的对象,包括数组都implement了Object类的方法。既然官方都说了Object是root了,那咱们看源码自然是从Object开始咯。


 那么再来看一下Object类里面具体有那么方法:

java方法本地方法
equals()registerNatives() 静态方法
toString()getClass()
void wait(long timeout, int nanos)hashCode()
wait()clone()
finalize()notify()
notifyAll()
wait(long timeout)

可以看到一共12个方法,一个一个来看:

  • java方法
  1. equals():

 equals是对于两个非null对象判断他们是不是相等的(注意,非null对象,因为null != 任何对象(包括null))。在Object类里面equals调用的就是“==”,也就是说在其他类没有重写equals方法时,equals等价于“==”。equals方法的特性是自反、对称的(离散数学的内容了),多次调用equals应该返回相同的结果。那么如果我们需要重写equals方法时也应该要保留这些特性。需要注意一点的是equals经常和hashCode拿来做比较。比如那道经典的面试题:为什么重写了equals一定要重写hashCode?这个题怎么说呢,如果这个类是保存到Hash等结构而且做为key时,或者我们有这种需求的时候,那么重写了equals方法就需要去重写hashCode,否则的话,我觉得是没有必要的,因为重写一个equals方法很简单,但是要重写一个hashcode方法是比较难的,因为我们要保证生成的hashCode要在数学上随机(可以参考HashMap等hash函数),实现起来是比较复杂的。所以在我们大部分的工作场景中HashMap的key都是使用String类型,很少有需要自定义key,也是就说绝大部分情况下,我们可以只重写equals而不需要重写hashCode。

  1. toString()

 这个方法就是把一个类扁平化,把类转成一个字符串。在使用println方法打印的时候会默认调用这个方法,了解即可。

  1. wait()和wait(long timeout, int nanos)

 这两个方法内部调用的都是本地方法wait(long timeout);
wait()方法调用的是本地方法:wait(0);
wait(long timeout , int nanos)调用的也是wait(long timeout)

  1. finalize()

 在对象被垃圾回收器回收之前会调用这个方法(不推荐使用)

  • 本地方法

  java的本地方法是java语言内部和外界环境交互的一些方法。本地方法由native修饰,表名这个方法是有实现体的,但是方法体不是由java实现。本地方法可以是以动态链接库的形式提供,由jvm调用。如果需要看到本地方法的具体实现,可以看看开源的jvm的代码(比如hotspot,由c++编写)。同时java虚拟机规范对本地方法栈所实现的语言,实现方式和数据结构没有要求,所有虚拟机可以自由的实现本地方法栈(hotspot就把本地方法栈和虚拟机栈合二为一)。由于native只有方法名,本人也没有看过jvm
的源码,所以这里只做一个简单的介绍。

1.registNatives()

 这个方法比较重要,很多类都有这个方法,理解起来也比较复杂,明天写篇博客专门讲这个。

2.getClass()

 拿到对象的Class对象。

3.clone()

 复制一个对象,这里就是经常有人问深拷贝和浅拷贝。个人觉得这个问题在java里面没什么意义,毕竟用的也不是很多。主要就是要对java的值传递(java里面只有值传递,没有引用传递)要理解的好。还有一个问题就是问java里面新建一个对象有哪些:new,反序列化,反射,clone(只知道这个4中,哈哈)。

4.notify() 、notifyAll()、wait()

 这三个方法都是和线程相关的,所以放到一起。
为了更好了理解这三个方法的用处,需要先了解java内部对线程状态的抽象,即java线程有几种状态。我从Thread类里面找到了答案:thread里面有个枚举类State,看一下State的源码:

public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED
} 

  可以看到一共6种状态,如果对这6中状态不太了解的,可以去搜一下,记得要看带6种转态的博客。有需要的同学还可以去看一下锁和监视器的区别。锁我相信大家都能够理解,但是这个监视器是什么江湖上流传着好多版本,有人说这就是一个管程,有人说他就是一个编程模型,还配了图,有人说java里面监视器就是锁等等等。我也不太懂这个,先打个todo,日后再来解释吧。
需要注意的是,在调用wait()这一系列方法之前,必须获取当前对象的监视器。通俗来件,就是说wait()方法需要而且只能放在synchronized{} 代码块里面,否则会抛出异常。

  wait()调用的是wait(0),wait(timeout,nanos)调用的也是wait(timeout),所以就讲讲wait(long timeout)。
那么wait(long timeout) 方法呢,使当前线程的进入WAITTING状态。如果过了timeout毫秒这个线程还没有被唤醒(notify),那么它就会自己醒过来,线程状态变成Runnable。如果timeout==0,那么这个线程只能等待别的线程调用notify()或notifyAll()。还需要注意的是,调用wait()方法,会释放这个线程占有的锁等资源。那么当这个线程被唤醒之后,需要重新去竞争锁,所以我们最好把wait()方法放进while循环。

  再来说一下调用wait(timeout)方法后会出现的4种情况。
1、别的线程调用了notify(),并且恰好选中了当前线程,那么当前线程被唤醒
2、别的线程调用了notifyAll(),那么当前线程被唤醒
3、别的线程调用了interrupt(),当前线程被唤醒,并且抛出InterruptedException(这个Exception不是RuntimeException).当前线程被唤醒
4、timeout== 0,如果timeout == 0,那么这个线程应该一直处于WAITING状态直到别的线程有以上3种操作。
5、notify(),notifyAll()
notify()是指从所有状态为WAITING的线程中随机选一个线程唤醒。
notifyAll()是指唤醒所有状态为WAITING的线程。

ok,终于写完了,写完了一半,预计明天把registNatives()这个方法讲清楚,这个类比较重要,对于我们了解java的本地方法会有很大帮助
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值