記錄一下今天在幫同事解決使用spring參數(shù)注入問(wèn)題的時(shí)候由于對(duì)泛型的理解不到位而遇到的坑。
如下代碼所示:
@RequestMapping(value="saveAll")
public ResponseMsg saveAll(List rules){
Rule rule=rules.get(0); //這行代碼在測(cè)試的時(shí)候報(bào)錯(cuò)了
......
}
這段代碼的意思是使用spring的參數(shù)注入功能自動(dòng)完成將前端傳過(guò)來(lái)的數(shù)據(jù)裝載到rules變量里面。
我剛開(kāi)始一直認(rèn)為這段代碼肯定是對(duì)的,然后就一直說(shuō)同事一定是前端傳過(guò)來(lái)的數(shù)據(jù)有錯(cuò),然后就各種檢查js,debug一步一步的查,發(fā)現(xiàn)前端傳過(guò)來(lái)的數(shù)據(jù)是正確的,后來(lái)我又想會(huì)不會(huì)是eclipse的debug功能有缺陷(原諒一個(gè)idea粉對(duì)eclipse的各種不屑),當(dāng)然繼續(xù)被打臉,因?yàn)槲以谖译娔X上debug時(shí)數(shù)據(jù)是一樣的,rules里面的元素居然是LinkedHashMap??!看著debug顯示的數(shù)據(jù),簡(jiǎn)直不能接受,我明明聲明了rules對(duì)象只能存Rules對(duì)象啊,怎么會(huì)裝其他對(duì)象?。?/p>
然后就真的沒(méi)轍了。。我就說(shuō)這個(gè)問(wèn)題我解決不了了,超出我認(rèn)知范圍啊,然后我們叫了一個(gè)正式員工過(guò)來(lái)幫我們看看。。他開(kāi)始也是按我們的步驟排錯(cuò),后來(lái)遇到和我們一樣的問(wèn)題,但是牛人終究是牛人,能想出來(lái)的導(dǎo)致問(wèn)題的因素也比我們多,他說(shuō)會(huì)不會(huì)是spring不支持這種帶泛型的自動(dòng)參數(shù)裝載啊,畢竟泛型是要被擦除的。。
擦除。。。泛型擦除。。。我靠,我終于知道是什么原因了。之前看了那么多關(guān)于泛型擦除的居然都沒(méi)有想到是這個(gè)問(wèn)題!!而且這種坑當(dāng)時(shí)也踩過(guò),居然沒(méi)聯(lián)想起來(lái),智商捉急。
關(guān)于泛型擦除的詳細(xì)介紹具體是什么我就不寫(xiě)在這篇文章里面了,大概就是在編譯前會(huì)執(zhí)行一系列的語(yǔ)法檢查,從而減少因?yàn)閺?qiáng)制類型轉(zhuǎn)換帶來(lái)的異常,但是編譯后的代碼是不含泛型的,會(huì)將泛型限制的元素類型給去掉。
也就是說(shuō)雖然我聲明了rules只能裝Rule類型的對(duì)象,但是代碼被編譯后,這個(gè)限制就沒(méi)有了!因?yàn)橥ㄟ^(guò)語(yǔ)法檢查rules里的元素確實(shí)是Rule類型的對(duì)象,所以并不需要在編譯后再去檢查。但是問(wèn)題來(lái)了,這種檢查只能檢查一些顯式生命的對(duì)象是不是Rule類型,而java是可以通過(guò)反射來(lái)動(dòng)態(tài)的生成對(duì)象的,sprng在參數(shù)注入的時(shí)候是通過(guò)反射實(shí)現(xiàn)前端參數(shù)自動(dòng)裝載入對(duì)象的相關(guān)屬性!!
所以這樣聲明的問(wèn)題在于,由于編譯時(shí)對(duì)rules內(nèi)元素類型的限制已經(jīng)被擦除了,所以spring并不知道反射成那種類型的對(duì)象,于是就默認(rèn)的用LinkedHashMap來(lái)裝載一個(gè)對(duì)象所有的屬性和值,于是rules里面的對(duì)象在運(yùn)行的時(shí)候?qū)嶋H上是LinkedHashMap?。。∷詓pring可能并不支持泛型參數(shù)或者需要指定其他條件才能正確的注入泛型參數(shù)(這個(gè)還沒(méi)有深究)。
至于以前踩過(guò)這方面的坑就是用Gson反序列化帶泛型的對(duì)象的時(shí)候需要額外指定一個(gè)參數(shù)來(lái)說(shuō)明集合里面的元素類型(具體的我忘了,這個(gè)有思路就好)。當(dāng)時(shí)也是覺(jué)得很奇妙,為什么不做得智能一點(diǎn)自己識(shí)別,我不是已經(jīng)通過(guò)泛型指定類型了么。當(dāng)時(shí)也就抱怨一下,沒(méi)有怎么多想,現(xiàn)在想起來(lái)還真是too young , too simple。。
這件事讓我明白不要盲目的相信自己的經(jīng)驗(yàn),計(jì)算機(jī)肯定是對(duì)的。經(jīng)驗(yàn)解決不了的問(wèn)題,就從原理一步一步去想,平時(shí)學(xué)的理論可能看起來(lái)沒(méi)什么用,就好像科普一樣,然而在解決一些問(wèn)題時(shí)確是一針見(jiàn)血。多聯(lián)想,發(fā)散思維才能在技術(shù)這條路上走得更遠(yuǎn)。