一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 從一道面試題看你對java的理解程度

從一道面試題看你對java的理解程度

2021-05-29 15:18juejin Java教程

這篇文章主要給大家介紹了關(guān)于如何從一道面試題看你對java的理解程度的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧

簡介

最近有點(diǎn)忙,很久沒更新文章了,后面會慢慢恢復(fù)...回顧正題

最近看到一篇文章,關(guān)于一道面試題,先看一下題目,如下:

java" id="highlighter_35982">
?
1
2
3
4
5
6
7
8
9
10
11
public static void main(string[] args) {
 integer a = 1;
 integer b = 2;
 system.out.printf("a = %s, b = %s\n", a, b);
 swap(a, b);
 system.out.printf("a = %s, b = %s\n", a, b);
 }
 
public static void swap(integer a, integer b) {
 // todo 實現(xiàn)
}

有人可能在沒經(jīng)過仔細(xì)考慮的情況下,給出以下的答案

?
1
2
3
4
5
6
7
8
9
// 特別提醒,這是錯誤的方式
// 特別提醒,這是錯誤的方式
// 特別提醒,這是錯誤的方式
public static void swap(integer a, integer b) {
 // todo 實現(xiàn)
 integer temp = a;
 a = b;
 b = temp;
}

很遺憾,這是錯誤的。重要的事注釋三遍

那么為什么錯誤,原因是什么?

想要搞清楚具體的原因,在這里你需要搞清楚以下幾個概念,如果這個概念搞清楚了,你也不會把上面的實現(xiàn)方法寫錯

  • 形參和實參
  • 參數(shù)值傳遞
  • 自動裝箱

所以,上面的問題先放一邊,先看一下這幾個概念

形參和實參

什么是形參?什么是實參?概念上的東西,參考教科書或者google去吧,下面直接代碼說明更加明顯

?
1
2
3
4
5
6
7
8
9
public void test() {
 int shi_can = 0;
 
 testa(shi_can);
}
 
public void testa(int xing_can) {
 
}

注:為了清楚的表達(dá)意思,我命名的時候并沒有按照java的駝峰規(guī)則命名,這里只是為了演示

通過上面的代碼很清楚的表達(dá)形參和實參的概念,在調(diào)用testa時,傳遞的就是實參,而在testa方法簽名中的參數(shù)為形參

從作用域上看,形參只會在方法內(nèi)部生效,方法結(jié)束后,形參也會被釋放掉,所以形參是不會影響方法外的

值傳遞和引用傳遞

值傳遞:傳遞的是實際值,像基本數(shù)據(jù)類型

引用傳遞:將對象的引用作為實參進(jìn)行傳遞

java基本類型數(shù)據(jù)作為參數(shù)是值傳遞,對象類型是引用傳遞

實參是可以傳遞給形參的,但是形參卻不能影響實參,所以,當(dāng)進(jìn)行值傳遞的情況下,改變的是形參的值,并沒有改變實參,所以無論是引用傳遞還是值傳遞,只要更改的是形參本身,那么都無法影響到實參的。對于引用傳遞而言,不同的引用可以指向相同的地址,通過形參的引用地址,找到了實際對象分配的空間,然后進(jìn)行更改就會對實參指向的對象產(chǎn)生影響

額,上面表述,可能有點(diǎn)繞,看代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 僅僅是一個java對象
public class inttype {
 
 private int value;
 
 public int getvalue() {
 return value;
 }
 
 public void setvalue(int value) {
 this.value = value;
 }
}
 
// main方法
public class inttypeswap {
 public static void main(string[] args) {
 
 // code_1
 inttype type1 = new inttype();
 type1.setvalue(1);
 
 inttype type2 = new inttype();
 type2.setvalue(2);
 // code_1
 
 swap1(type1, type2);
 system.out.printf("type1.value = %s, type2.value = %s", type1.getvalue(), type2.getvalue());
 swap2(type1, type2);
 system.out.println();
 system.out.printf("type1.value = %s, type2.value = %s", type1.getvalue(), type2.getvalue());
 }
 
 public static void swap2(inttype type1, inttype type2) {
 int temp = type1.getvalue();
 type1.setvalue(type2.getvalue());
 type2.setvalue(temp);
 }
 
 public static void swap1(inttype type1, inttype type2) {
 inttype type = type1;
 type1 = type2;
 type2 = type;
 }
}

在main方法中,code_1中間的代碼為聲明了兩個對象,分別設(shè)置value為1和2,而swap1和swap2兩個方法的目的是為了交互這兩個對象的value值

先思考一下,應(yīng)該輸出的結(jié)果是什么

...

...

?
1
2
type1.value = 1, type2.value = 2
type1.value = 2, type2.value = 1

從輸出結(jié)果來看swap1并沒有達(dá)到目的,回頭看一下

?
1
2
3
4
5
swap1public static void swap1(inttype type1, inttype type2) {
 inttype type = type1;
 type1 = type2;
 type2 = type;
 }

從值傳遞的角度來看,對象參數(shù)傳遞采用的是引用傳遞,那么type1和type2傳遞過來的是指向?qū)ο蟮囊茫诜椒▋?nèi)部,直接操作形參,交換了形參的內(nèi)容,這樣形參改變,都是并沒有對實參產(chǎn)生任何影響,也沒有改變對象實際的值,所以,結(jié)果是無法交換

而對于swap2,對象引用作為形參傳遞過來后,并沒有對形參做任何的改變,而是直接操作了形參所指向的對象實際地址,那這樣,無論是實參還是其他地方,只要是指向該對象的所有的引用地址對應(yīng)的值都會改變

自動裝箱

看我上面的那個例子的swap1,是不是頓時覺得與上面的面試題的錯誤做法非常相似了,是的,錯誤的原因是一模一樣的,就是稍微有一點(diǎn)區(qū)別,就是integer不是new出來的,而是自動裝箱的一個對象,那么什么是自動裝箱呢?jdk到底做了什么事?

如果你不想知道為什么,只想知道結(jié)果,那么我就直說,自動裝箱就是jdk調(diào)用了integer的valueof(int)的方法,很簡單,看源碼

?
1
2
3
4
5
public static integer valueof(int i) {
 if (i >= integercache.low && i <= integercache.high)
 return integercache.cache[i + (-integercache.low)];
 return new integer(i);
 }

上面那些如果不想深究可以忽略,就看最后一句,是不是明白了什么呢。沒錯,也是new出來一個對象,如果想知道上面的代碼做了什么處理,可以參考 long==long有趣的現(xiàn)象 這篇文章,里面有介紹類似的

好了,有人可能會問,為什么會知道自動裝箱調(diào)用的是valueof方法,這里其他人怎么知道的我不清楚,我是通過查看反編譯的字節(jié)碼指令知道的

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(string[] args) {
 integer a = 1;
 integer b = 2;
 system.out.printf("a = %s, b = %s\n", a, b);
 swap(a, b);
 system.out.printf("a = %s, b = %s\n", a, b);
 }
 
 public static void swap(integer a, integer b) {
 integer temp = a;
 a = b;
 b = temp;
 }

反編譯出來的結(jié)果為

從一道面試題看你對java的理解程度

對比一下可以很清楚的看到valueof(int)方法被調(diào)用

回歸

好,現(xiàn)在回歸正題了,直接操作形參無法改變實際值,而integer又沒有提供set方法,那是不是無解了呢?我很好奇如果有人以下這樣寫,面試官會有什么反應(yīng)

?
1
2
3
4
public static void swap(integer a, integer b) {
 // todo 實現(xiàn)
 // 無解,
 }

既然出了肯定是有解的,可以實現(xiàn),回頭看看,在上面swap2的那個例子中是通過set方法來改變值的,那么integer有沒有提供呢?答案沒有(我沒找到)

那就先看看源碼

?
1
2
3
4
5
private final int value;
...
public integer(int value) {
 this.value = value;
 }

這是integer的構(gòu)造函數(shù),可以看到integer對象實際值是用value屬性來存儲的,但是這個value是被final修飾的,沒辦法繼續(xù)找,value沒有提供任何的set方法。既然在萬法皆不通的情況下,那就只能動用反射來解決問題

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void swap(integer a, integer b) {
 int temp = a.intvalue();
 try {
 field value = integer.class.getdeclaredfield("value");
 value.setaccessible(true);
 value.set(a, b);
 value.set(b, temp);
 
 } catch (nosuchfieldexception e) {
 e.printstacktrace();
 } catch (illegalaccessexception e) {
 e.printstacktrace();
 }
 }

現(xiàn)在感覺很開心,終于找到解決方案,可是當(dāng)你執(zhí)行的時候,從輸出結(jié)果你會發(fā)現(xiàn),jdk在跟我開玩笑嗎

?
1
2
a = 1, b = 2
a = 2, b = 2

為什么會出現(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就可以跳過緩存,所以代碼改成如下即可

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void swap(integer a, integer b) {
 int temp = a.intvalue();
 try {
 field value = integer.class.getdeclaredfield("value");
 value.setaccessible(true);
 value.set(a, b);
 value.set(b, new integer(temp));
 
 } catch (nosuchfieldexception e) {
 e.printstacktrace();
 } catch (illegalaccessexception e) {
 e.printstacktrace();
 }
 }

至此,這道題完美結(jié)束

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。

原文鏈接:https://juejin.im/post/5b8d21b651882542b20591af

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 花唇肿胀无法合拢双性 | 赤坂丽女医bd无删减在线观看 | 四虎精品成人免费观看 | 海派甜心完整版在线观看 | 日韩在线a视频免费播放 | 91最新高端约会系列178 | 日韩精品中文字幕久久 | 亚洲天堂日韩在线 | 视频在线观看一区二区三区 | 久久久精品免费免费直播 | 欧美久久久久久久一区二区三区 | 鬼吹灯之天星术免费观看 | 亚洲高清中文字幕精品不卡 | japan孕妇孕交| 日本视频免费看 | 96日本xxxxxxxxx70| 精品视频在线免费播放 | 亚洲精品第二页 | 免费人成网址在线观看国内 | 91传媒在线观看 | 好男人在线观看免费高清2019韩剧 | 91短视频破解版 | 美女张开大腿让男人桶 | 日韩成人免费aa在线看 | 国产日韩欧美在线观看不卡 | 欧美怡红院视频一区二区三区 | 欧美一区二区三区四区在线观看 | 色悠久久久久综合网小说 | 深夜成人| 国产90后美女露脸在线观看 | 99ri精品 | 国产成人在线影院 | 精东影业传媒全部作品 | 成人国产第一区在线观看 | 俄罗斯妈妈235 | 包射屋| 免费片在线观看 | 四虎comwww最新地址 | 色花堂国产精品首页第一页 | 亚洲精美视频 | 久久嫩草影院网站 |