摘要:無(wú)論在中出現(xiàn)什么,都可以認(rèn)為它是對(duì)象除了八大基本數(shù)據(jù)類型。讓當(dāng)前線程等待某個(gè)對(duì)象的鎖,當(dāng)然應(yīng)該通過(guò)這個(gè)對(duì)象來(lái)操作了。但是要注意的是方法調(diào)用后,被喚醒的線程不會(huì)立馬獲得到鎖對(duì)象。主要的區(qū)別在于在釋放同時(shí),釋放了對(duì)象鎖的控制。
前言
五一回家又?jǐn)喔艘粋€(gè)放假時(shí)間了~~~
只有光頭才能變強(qiáng)
回顧前面:
ThreadLocal就是這么簡(jiǎn)單
多線程三分鐘就可以入個(gè)門了!
多線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線程事半功倍
Java鎖機(jī)制了解一下
AQS簡(jiǎn)簡(jiǎn)單單過(guò)一遍
Lock鎖子類了解一下
之前花了點(diǎn)之間時(shí)間去搞多線程的基礎(chǔ)知識(shí)了,難呀難呀難呀....打算還寫(xiě)一篇線程池的就暫時(shí)將多線程系列停止了...
今天中午在逛簡(jiǎn)書(shū)的時(shí)候發(fā)現(xiàn)一些大廠也會(huì)問(wèn)Object對(duì)象里面有什么方法(也算是一個(gè)知識(shí)點(diǎn)吧),Object我還沒(méi)去認(rèn)真復(fù)習(xí)過(guò),于是這篇主要看看Object對(duì)象有什么要注意的地方~
那么接下來(lái)就開(kāi)始吧,如果文章有錯(cuò)誤的地方請(qǐng)大家多多包涵,不吝在評(píng)論區(qū)指正哦~
一、Object對(duì)象簡(jiǎn)介聲明:本文都是使用JDK1.8
我們學(xué)Java的知道,Java是一門面向?qū)ο蟮恼Z(yǔ)言。無(wú)論在Java中出現(xiàn)什么,都可以認(rèn)為它是對(duì)象(除了八大基本數(shù)據(jù)類型。當(dāng)然了,八大基本數(shù)據(jù)類型也能裝箱成為對(duì)象):
而Object就是這些對(duì)象的最高級(jí)別的,所有的Java對(duì)象都隱式地繼承了Object對(duì)象(不用顯示寫(xiě)extends繼承)
所有的Java對(duì)象都擁有Object默認(rèn)的方法。
那么我們看看Object有什么方法:
其實(shí)就可以歸納成幾個(gè):
registerNatives()【底層實(shí)現(xiàn)、不研究】
hashCode()
equals(Object obj)
clone()
toString()
notify()
notifyAll()
wait(long timeout)【還有重載了兩個(gè)】
finalize()
Object一共有11個(gè)方法,其中一個(gè)為底層的實(shí)現(xiàn)registerNatives(),其中兩個(gè)wait()和wait(long timeout, int nanos)重載方法。
所以我們真正需要看的就是8個(gè)方法
還有一個(gè)屬性:
public final native Class> getClass();二、equals和hashCode方法
equals和hashCode方法可以說(shuō)是面試的重點(diǎn)題了,配合著String可以說(shuō)在面試題中哪都有它們的存在。
首先,我們來(lái)看看equals和hashCode在Object中原生的實(shí)現(xiàn)吧:
hashCode:
public native int hashCode();
equals:
public boolean equals(Object obj) { return (this == obj); }
看上去都非常簡(jiǎn)單:
hashCode()由native方法底層實(shí)現(xiàn)了。
equals()就直接==判斷是否相等了。
想要更加清晰它們究竟是做什么的,我們來(lái)讀讀它的注釋:
根據(jù)注釋我們可以總結(jié)以下的要點(diǎn):
重寫(xiě)equals()方法,就必須重寫(xiě)hashCode()的方法
equals()方法默認(rèn)是比較對(duì)象的地址,使用的是==等值運(yùn)算符
hashCode()方法對(duì)底層是散列表的對(duì)象有提升性能的功能
同一個(gè)對(duì)象(如果該對(duì)象沒(méi)有被修改):那么重復(fù)調(diào)用hashCode()那么返回的int是相同的!
hashCode()方法默認(rèn)是由對(duì)象的地址轉(zhuǎn)換而來(lái)的
equals()方法還有5個(gè)默認(rèn)的原則:
自反性--->只要對(duì)象的不為null,x.equals(x)應(yīng)該返回的是true
一致性--->只要對(duì)象沒(méi)有被修改,那么多次調(diào)用還是返回對(duì)應(yīng)的結(jié)果!
傳遞性--->x.equals(y)和y.equals(z)都返回true,那么可以得出:x.equals(z)返回true
對(duì)稱性--->x.equals(y)和y.equals(x)結(jié)果應(yīng)該是相等的。
傳入的參數(shù)為null,返回的是false
為啥說(shuō)hashCode()以散列表為底層帶來(lái)性能的提升是很容易理解的。我們?cè)賮?lái)回顧一下HashMap的插入:
如果hash值都不相等,那么可以直接判斷該key是不相等的了!
2.1equals和hashCode方法重寫(xiě)equals()方法默認(rèn)是比較對(duì)象的地址,使用的是==等值運(yùn)算符。但是按我們正常開(kāi)發(fā)來(lái)說(shuō),比較的是對(duì)象地址是沒(méi)有意義的。
一般地,如果我們有兩個(gè)Address對(duì)象,只要這兩個(gè)對(duì)象的省號(hào)、城市號(hào)、街道號(hào)相等,我們就認(rèn)為這兩個(gè)對(duì)象相等了!
2.2String實(shí)現(xiàn)的equals和hashCode方法我們?cè)诔鯇W(xué)的時(shí)候可能就聽(tīng)過(guò)了:String已經(jīng)實(shí)現(xiàn)了equals和hashCode方法了。
這也就是為什么,我們可以直接使用String.equals()來(lái)判斷兩個(gè)字符串是否相等!
下面我們就來(lái)看看它的實(shí)現(xiàn)吧:
三、toString方法接下來(lái)我們看看toString方法,也十分簡(jiǎn)單:
toString方法主要是用來(lái)標(biāo)識(shí)該對(duì)象的:
從上面的結(jié)果我們都可以看出來(lái):得出的結(jié)果我們并不能看到什么東西~
于是我們一般都重寫(xiě)toString(),那么打印出的結(jié)果就很方便我們調(diào)試了!
@Override public String toString() { return "Address{" + "provinceNo=" + provinceNo + ", cityNo=" + cityNo + ", streetNo=" + streetNo + "}"; }
下面的結(jié)果看起來(lái)就好多了:
四、clone方法我們也來(lái)看看它的頂部注釋:
看了上面的注釋我們可以總結(jié)以下的要點(diǎn):
clone方法用于對(duì)象的克隆,一般想要克隆出的對(duì)象是獨(dú)立的(與原有的對(duì)象是分開(kāi)的)
深拷貝指的是該對(duì)象的成員變量(如果是可變引用)都應(yīng)該克隆一份,淺拷貝指的是成員變量沒(méi)有被克隆一份
下面我們來(lái)看一下淺拷貝:拷貝了Employee對(duì)象,但是其成員變量hireday沒(méi)有被克隆出去,所以指向的還是同一個(gè)Date對(duì)象!
4.1clone用法那么我們?nèi)绾慰寺?duì)象呢?無(wú)論是淺拷貝還是深拷貝都是這兩步:
克隆的對(duì)象要實(shí)現(xiàn)Cloneable接口
重寫(xiě)clone方法,最好修飾成public
淺拷貝:僅僅拷貝了Person對(duì)象,而date沒(méi)有拷貝!
public class Person implements Cloneable { // 可變的成員變量 private Date date; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } }
深拷貝:不僅拷貝了Person對(duì)象,也拷貝了date成員變量
public class Person implements Cloneable { // 可變的成員變量 public Date date; @Override public Object clone() throws CloneNotSupportedException { // 拷貝Person對(duì)象 Person person = (Person) super.clone(); // 將可變的成員變量也拷貝 person.date = (Date) date.clone(); // 返回拷貝的對(duì)象 return person; } }4.2clone疑問(wèn)進(jìn)一步學(xué)習(xí)protected
不知道有沒(méi)有人跟我有相同的疑問(wèn):
我只想要淺拷貝,能不能直接調(diào)用該對(duì)象.clone()來(lái)實(shí)現(xiàn)?
比如我現(xiàn)在有個(gè)Address對(duì)象:
public class Address { private int provinceNo; private int cityNo; private int streetNo; public Address() { } public Address(int provinceNo, int cityNo, int streetNo) { this.provinceNo = provinceNo; this.cityNo = cityNo; this.streetNo = streetNo; } }
下面的代碼你們認(rèn)為如何?
Address address = new Address(1, 2, 3); address.clone();
我們都知道:
protected修飾的類和屬性,對(duì)于自己、本包和其子類可見(jiàn)
可能會(huì)想:clone()方法是定義在Object類上的(以protected來(lái)修飾),而我們自定義的Address對(duì)象隱式繼承著Object(所有的對(duì)象都是Object的子類),那么子類調(diào)用Object以protected來(lái)修飾clone()是完全沒(méi)問(wèn)題的
但是,IDE現(xiàn)實(shí)告訴我,這編譯就不通過(guò)了!
出現(xiàn)錯(cuò)誤的原因我立馬就想到:是不是我對(duì)protected修飾符出現(xiàn)了偏差?
protected修飾的類和屬性,對(duì)于自己、本包和其子類可見(jiàn),這句話本身是沒(méi)有錯(cuò)的。但是還需要補(bǔ)充:對(duì)于protected的成員或方法,要分子類和超類是否在同一個(gè)包中。與基類不在同一個(gè)包中的子類,只能訪問(wèn)自身從基類繼承而來(lái)的受保護(hù)成員,而不能訪問(wèn)基類實(shí)例本身的受保護(hù)成員。
上面的代碼就錯(cuò)在:Address與Object不是在同一個(gè)包下的,而Address直接訪問(wèn)了Object的clone方法。這是不行的。
下面我截兩張圖再來(lái)給你們看看(看完圖再看上面的描述,就能理解了):
圖片來(lái)源和更多的展開(kāi)閱讀:https://blog.csdn.net/wangyanguiyiyang/article/details/49800493
五、wait和notify方法wait和notify方法其實(shí)就是Java給我們提供讓線程之間通信的API。
按照慣例我們還是來(lái)看注釋怎么說(shuō)吧:
wait方法:
notify方法:
notifyAll()方法:
看完上面的注釋我們可以總結(jié)以下的要點(diǎn):
無(wú)論是wait、notify還是notifyAll()都需要由監(jiān)聽(tīng)器對(duì)象(鎖對(duì)象)來(lái)進(jìn)行調(diào)用
簡(jiǎn)單來(lái)說(shuō):他們都是在同步代碼塊中調(diào)用的,否則會(huì)拋出異常!
notify()喚醒的是在等待隊(duì)列的某個(gè)線程(不確定會(huì)喚醒哪個(gè)),notifyAll()喚醒的是等待隊(duì)列所有線程
導(dǎo)致wait()的線程被喚醒可以有4種情況
該線程被中斷
wait()時(shí)間到了
被notify()喚醒
被notifyAll()喚醒
調(diào)用wait()的線程會(huì)釋放掉鎖
其實(shí)總結(jié)完上面的并不會(huì)有比較深刻的印象,可以嘗試著回答幾個(gè)問(wèn)題來(lái)加深對(duì)wait()和notify()的理解。
5.1為什么wait和notify在Object方法上?從一開(kāi)始我們就說(shuō)了:wait()和notify()是Java給我們提供線程之間通信的API,既然是線程的東西,那什么是在Object類上定義,而不是在Thread類上定義呢?
因?yàn)槲覀兊?strong>鎖是對(duì)象鎖【要是忘記的同學(xué)可回顧:Java鎖機(jī)制了解一下】,每個(gè)對(duì)象都可以成為鎖。讓當(dāng)前線程等待某個(gè)對(duì)象的鎖,當(dāng)然應(yīng)該通過(guò)這個(gè)對(duì)象來(lái)操作了。
鎖對(duì)象是任意的,所以這些方法必須定義在Object類中
5.2notify方法調(diào)用后,會(huì)發(fā)生什么?上面已經(jīng)說(shuō)了,notify會(huì)喚醒某個(gè)處于等待隊(duì)列的線程。
但是要注意的是:
notify方法調(diào)用后,被喚醒的線程不會(huì)立馬獲得到鎖對(duì)象。而是等待notify的synchronized代碼塊執(zhí)行完之后才會(huì)獲得鎖對(duì)象
5.3sleep和wait有什么區(qū)別?Thread.sleep()與Object.wait()二者都可以暫停當(dāng)前線程,釋放CPU控制權(quán)。
主要的區(qū)別在于Object.wait()在釋放CPU同時(shí),釋放了對(duì)象鎖的控制。
而Thread.sleep()沒(méi)有對(duì)鎖釋放
參考資料:
https://blog.csdn.net/lingzhm/article/details/44940823
http://www.cnblogs.com/dolphin0520/p/3920385.html
https://www.cnblogs.com/eer123/p/7880789.html
https://www.jianshu.com/p/f4454164c017
六、finalize()方法finalize()方法將在垃圾回收器清除對(duì)象之前調(diào)用,但該方法不知道何時(shí)調(diào)用,具有不定性
一般我們都不會(huì)重寫(xiě)它~
一個(gè)對(duì)象的finalize()方法只會(huì)被調(diào)用一次,而且finalize()被調(diào)用不意味著gc會(huì)立即回收該對(duì)象,所以有可能調(diào)用finalize()后,該對(duì)象又不需要被回收了,然后到了真正要被回收的時(shí)候,因?yàn)榍懊嬲{(diào)用過(guò)一次,所以不會(huì)調(diào)用finalize(),產(chǎn)生問(wèn)題。
參考資料:
https://segmentfault.com/q/1010000000094660
進(jìn)階的資料:
https://www.cnblogs.com/Smina/p/7189427.html
http://www.importnew.com/23913.html
https://zhuanlan.zhihu.com/p/29522201
https://zhuanlan.zhihu.com/p/25698745
七、總結(jié)總的來(lái)說(shuō)也算是把Object看了一遍了,不至于一下子把它的方法給忘了~~~在學(xué)習(xí)的過(guò)程中也遇到過(guò)問(wèn)題,最明顯的是對(duì)protected修飾符又加深了一次理解。
參考資料:
《Java核心技術(shù)卷一》
如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y。為了大家方便,剛新建了一下qq群:742919422,大家也可以去交流交流。謝謝支持了!希望能多介紹給其他有需要的朋友
文章的目錄導(dǎo)航:
https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/71104.html
摘要:什么交互都處理不了怎么辦簡(jiǎn)化復(fù)雜度復(fù)雜邏輯后端處理的多線程上面都是的做法,但是也是處理這種問(wèn)題的一把好手。換一種思路,上面就是利用實(shí)現(xiàn)一種偽多線程的概念。 教科書(shū)里面的setTimeout 定義很簡(jiǎn)單 setTimeout() 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式。 廣泛應(yīng)用場(chǎng)景 定時(shí)器,輪播圖,動(dòng)畫(huà)效果,自動(dòng)滾動(dòng)等等 上面一些應(yīng)該是setTimeout在大家心中的樣子...
摘要:權(quán)威指南第六版關(guān)于閉包的說(shuō)明采用詞法作用域,也就是說(shuō)函數(shù)的執(zhí)行依賴于變量的作用域,這個(gè)作用域是在函數(shù)定義時(shí)決定的,而不是函數(shù)調(diào)用時(shí)決定的。閉包這個(gè)術(shù)語(yǔ)的來(lái)源指函數(shù)變量可以被隱藏于作用域鏈之內(nèi),因此看起來(lái)是函數(shù)將變量包裹了起來(lái)。 最近打算換工作,所以參加了幾次面試(國(guó)內(nèi)比較知名的幾家互聯(lián)網(wǎng)公司)。在面試的過(guò)程中每當(dāng)被問(wèn)起閉包,我都會(huì)說(shuō)閉包是作用域的問(wèn)題?令人驚訝的是幾乎無(wú)一例外的當(dāng)我提到...
摘要:所以說(shuō)我們的線程最好是交由線程池來(lái)管理,這樣可以減少對(duì)線程生命周期的管理,一定程度上提高性能。線程池不接收新任務(wù),不處理已添加的任務(wù),并且會(huì)中斷正在處理的任務(wù)。當(dāng)所有的任務(wù)已終止,記錄的任務(wù)數(shù)量為,線程池會(huì)變?yōu)闋顟B(tài)。線程池徹底終止的狀態(tài)。 前言 只有光頭才能變強(qiáng) 回顧前面: ThreadLocal就是這么簡(jiǎn)單 多線程三分鐘就可以入個(gè)門了! 多線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線程事半功倍...
摘要:如果構(gòu)造函數(shù)有返回值呢一般情況下構(gòu)造函數(shù)沒(méi)有返回值,但是我們依舊可以得到該對(duì)象的實(shí)例如果構(gòu)造函數(shù)有返回值,憑直覺(jué)來(lái)說(shuō)情況應(yīng)該會(huì)不一樣。歡迎光臨小弟博客我的博客原文你真的弄明白了嗎參考再談面向?qū)ο缶幊痰膶?shí)例化與繼承請(qǐng)停止使用關(guān)鍵字 好久沒(méi)有寫(xiě)點(diǎn)東西了,總覺(jué)得自己應(yīng)該寫(xiě)點(diǎn)牛逼的,卻又不知道如何下筆。既然如此,還是回歸最基本的吧,今天就來(lái)說(shuō)一說(shuō)這個(gè)new。關(guān)于javascript的new關(guān)鍵...
閱讀 2002·2023-04-26 01:44
閱讀 1337·2021-11-12 10:34
閱讀 1692·2021-09-09 09:33
閱讀 1814·2019-08-30 15:44
閱讀 2955·2019-08-30 13:49
閱讀 2265·2019-08-29 15:26
閱讀 1000·2019-08-26 13:30
閱讀 1482·2019-08-23 18:15