這一道面試題就考驗了你對Java的理解程度
簡介
最近看到一篇文章,關(guān)于一道面試題,先看一下題目,如下:
有人可能在沒經(jīng)過仔細(xì)考慮的情況下,給出以下的答案
很遺憾,這是錯誤的。重要的事注釋三遍
那么為什么錯誤,原因是什么?
想要搞清楚具體的原因,在這里你需要搞清楚以下幾個概念,如果這個概念搞清楚了,你也不會把上面的實(shí)現(xiàn)方法寫錯
形參和實(shí)參
參數(shù)值傳遞
自動裝箱
所以,上面的問題先放一邊,先看一下這幾個概念
形參和實(shí)參
什么是形參?什么是實(shí)參?
概念上的東西,參考教科書或者google去吧,下面直接代碼說明更加明顯
注:為了清楚的表達(dá)意思,我命名的時候并沒有按照java的駝峰規(guī)則命名,這里只是為了演示
通過上面的代碼很清楚的表達(dá)形參和實(shí)參的概念,在調(diào)用testA時,傳遞的就是實(shí)參,而在testA方法簽名中的參數(shù)為形參
從作用域上看,形參只會在方法內(nèi)部生效,方法結(jié)束后,形參也會被釋放掉,所以形參是不會影響方法外的
值傳遞和引用傳遞
值傳遞:傳遞的是實(shí)際值,像基本數(shù)據(jù)類型
引用傳遞:將對象的引用作為實(shí)參進(jìn)行傳遞
java基本類型數(shù)據(jù)作為參數(shù)是值傳遞,對象類型是引用傳遞
實(shí)參是可以傳遞給形參的,但是形參卻不能影響實(shí)參,所以,當(dāng)進(jìn)行值傳遞的情況下,改變的是形參的值,并沒有改變實(shí)參,所以無論是引用傳遞還是值傳遞,只要更改的是形參本身,那么都無法影響到實(shí)參的。對于引用傳遞而言,不同的引用可以指向相同的地址,通過形參的引用地址,找到了實(shí)際對象分配的空間,然后進(jìn)行更改就會對實(shí)參指向的對象產(chǎn)生影響
額,上面表述,可能有點(diǎn)繞,看代碼
在main方法中,CODE_1中間的代碼為聲明了兩個對象,分別設(shè)置value為1和2,而swap1和swap2兩個方法的目的是為了交互這兩個對象的value值
先思考一下,應(yīng)該輸出的結(jié)果是什么
…
…
從輸出結(jié)果來看swap1并沒有達(dá)到目的,回頭看一下swap1
從值傳遞的角度來看,對象參數(shù)傳遞采用的是引用傳遞,那么type1和type2傳遞過來的是指向?qū)ο蟮囊?,在方法?nèi)部,直接操作形參,交換了形參的內(nèi)容,這樣形參改變,都是并沒有對實(shí)參產(chǎn)生任何影響,也沒有改變對象實(shí)際的值,所以,結(jié)果是無法交換
而對于swap2,對象引用作為形參傳遞過來后,并沒有對形參做任何的改變,而是直接操作了形參所指向的對象實(shí)際地址,那這樣,無論是實(shí)參還是其他地方,只要是指向該對象的所有的引用地址對應(yīng)的值都會改變。更多面試題,歡迎下方評論!
自動裝箱
看我上面的那個例子的swap1,是不是頓時覺得與上面的面試題的錯誤做法非常相似了,是的,錯誤的原因是一模一樣的,就是稍微有一點(diǎn)區(qū)別,就是Integer不是new出來的,而是自動裝箱的一個對象,那么什么是自動裝箱呢?jdk到底做了什么事?
如果你不想知道為什么,只想知道結(jié)果,那么我就直說,自動裝箱就是jdk調(diào)用了Integer的valueOf(int)的方法,很簡單,看源碼
上面那些如果不想深究可以忽略,就看最后一句,是不是明白了什么呢。沒錯,也是new出來一個對象。
好了,有人可能會問,為什么會知道自動裝箱調(diào)用的是valueOf方法,這里其他人怎么知道的我不清楚,我是通過查看反編譯的字節(jié)碼指令知道的
反編譯出來的結(jié)果為

對比一下可以很清楚的看到valueOf(int)方法被調(diào)用
回歸
好,現(xiàn)在回歸正題了,直接操作形參無法改變實(shí)際值,而Integer又沒有提供set方法,那是不是無解了呢?我很好奇如果有人以下這樣寫,面試官會有什么反應(yīng)
既然出了肯定是有解的,可以實(shí)現(xiàn),回頭看看,在上面swap2的那個例子中是通過set方法來改變值的,那么Integer有沒有提供呢?答案沒有(我沒找到)
那就先看看源碼
這是Integer的構(gòu)造函數(shù),可以看到Integer對象實(shí)際值是用value屬性來存儲的,但是這個value是被final修飾的,沒辦法繼續(xù)找,value沒有提供任何的set方法。既然在萬法皆不通的情況下,那就只能動用反射來解決問題
現(xiàn)在感覺很開心,終于找到解決方案,可是當(dāng)你執(zhí)行的時候,從輸出結(jié)果你會發(fā)現(xiàn),jdk在跟我開玩笑嗎
為什么會出現(xiàn)這種情況,無奈,調(diào)試會發(fā)現(xiàn)是在value.set的時候?qū)nteger的緩存值改變了,因為value.set(Object v1, Object v2)兩個參數(shù)都是對象類型,所以temp會進(jìn)行自動裝箱操作,會調(diào)用valueOf方法,這樣會獲取到錯誤的緩存值,所以,為了避免這種情況,就只能不需要調(diào)用緩存值,直接new Integer就可以跳過緩存,所以代碼改成如下即可
至此,這道題完美結(jié)束
這些年做Java開發(fā)我整理了一份完整的java的系統(tǒng)化資料,從Javase- ssm-springcloud,包括了面試題,PDF電子書等等,以及我自身之前的一個面試文案和知識點(diǎn)補(bǔ)充,如果你需要一本全面的Java書,如果你想學(xué)習(xí)Java,如果你想找到一份好的工作,那么緣分就來了,有需要的朋友可以評論區(qū)留言?,這里也祝愿大家最終都能夠?qū)W有所成,早日找到滿意的工作!
諾,干貨來了,請接收:
適合初學(xué)者學(xué)習(xí)的2021最新Java學(xué)習(xí)視頻,書籍,面試題,PDF文檔,都是經(jīng)典干貨!