一. Object
少年你有没有发现,在你使用心爱的idea快捷创建对象时,Alt+Ins后弹出来的选项除了你常用的构造方法和getset方法,还有其他我们最常用的方法equals, hashCode以及toString
其中这三个方法都隶属于Object类,下面我们就来了解Object
1.定义
Object 是类层次结构的根,每个类都可以将 Object 作为超类
也就是说所有类都直接或者间接继承于Object类;换句话说,该类所具备的方法,其他所有类都继承了,其他类都可以重写其中的方法
2.常见方法
打开java API文档,我们可以看到Object的全部方法
其中我们只需先了解下面三个方法,其余方法多用于多线程
⑴toString
toString:返回该对象的字符串表示
①源码
如图:我创建了一个Student对象s,并输出打印了s. toString
下面我们定位到toString的源码
其中调用的方法是什么我们不需要了解,我们只需要知道每一部分的含义,其中返回的字符串我们称之为对象的内存地址值
当然获取对象的内存地址值没有太大的意义,
获取对象的成员变量的字符串拼接形式才算有意义,那么我们就需要在对象中重写toString方法
如图:重写toString方法输出打印s,此时我们就可以清楚的看到Student的成员变量值
因此重写toString方法的意义就是
方便的展示对象中的属性值
⑵equals
equals:指示其他某个对象是否与此对象"相等"
①源码
我们在比较引用数据类型时(如int)使用的是"==",比较引用数据类型时(比如String),使用的一般都是equals,那我可不可以引用数据类型也用"=="? equals的底层是用什么比较的?
如图:打开Object中equals的源码,我们发现,equals的底层比较居然也是用"=="比较的!
好!那我创建两个Student对象,来比较一下看他们是否相等
如图:我创建了两个对象,变量都赋值为"张三",我想要比较他俩的属性是否相等
运行发现,诶?俩属性值都是"张三",怎么比较结果是false?那我们来打印一下他们的值
如图:打印发现打印的是地址值
因此引用数据类型"=="比较的是地址值
那我想要比较对象的属性值,就要重写equals方法
接下来我们来看Objects中的equals方法
发现Objects中的equals方法比Object中的equals方法多了一个调用者的非空判断
⑶hashCode
hashCode:返回该对象的哈希码值
什么是哈希码值?
哈希码值就是对象的整数表现形式,哈希表就是根据键的哈希值来进行去重的
要注意的是
①如果没有重写hashCode方法,不同对象的哈希值就不同
因为Objects中的哈希值是根据对象的地址值计算的,不同对象的地址值不同,哈希值也就不同,也就无法进行去重
②重写方法后,对象的属性值相同哈希值就相同
重写后的hashCode方法底层调用的是Arrays中的hashCode,下面我们来看看源码
如图:在JavaBean中重写的hashCode方法将对象的属性值传入
数组a就是属性值,在hashCode中根据属性值计算哈希值并返回
③哈希碰撞
哈希碰撞就是不同的哈希值计算可能出现哈希值相等的情况
3.小结
⑴输出对象的地址值一般没有意义,我们可以通过重写toString方法去输出对应的成员变量信息
注:一般情况下Jdk所提供的类都会重写Object类中的toString方法,如ArrayList
⑵比较对象的地址值是没有意义的,因此一般情况下我们都会重写Object类中的equals方法以此来比较对象的属性值
⑶不同对象的哈希值不同,若要进行对象的去重,就要重写hashCode方法
二.多线程协作中的Object
前面我们了解了Object中最基础的三个方法,下面我们就来看看在多线程协作中最常用的两个方法wait和notify
1.生产者和消费者模式
生产者和消费者模式是一个十分经典的多线程协作的模式,又叫做等待唤醒机制,打破了线程的随机机制,让多个线程轮流执行
⑴生产者和消费者的逻辑
我们可以把生产者比作厨师,消费者比作顾客,厨师做好食物放到桌子上,顾客看到桌子上的食物就吃
当生产者进入时,若发现桌子上有食物,那么它就会沉睡等待,若发现桌子上没有食物,那么它就会生产并叫醒消费者
当消费者进入时,若发现桌子上没有食物,那么它就会沉睡等待;若发现桌子上有食物,那么它就会消费并叫醒生产者
⑵wait和notify
wait在此模式下就是沉睡线程,notify在此模式下就是唤醒线程
注: wait和notify必须在同步代码块或同步方法中使用