日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java暗箱操作之自動裝箱與拆箱

我以前在寫Android項目的時候,估計寫得最多最熟練的幾句話就是:

創(chuàng)新互聯(lián)一直通過網(wǎng)站建設(shè)和網(wǎng)站營銷幫助企業(yè)獲得更多客戶資源。 以"深度挖掘,量身打造,注重實效"的一站式服務(wù),以成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、移動互聯(lián)產(chǎn)品、營銷型網(wǎng)站服務(wù)為核心業(yè)務(wù)。十載網(wǎng)站制作的經(jīng)驗,使用新網(wǎng)站建設(shè)技術(shù),全新開發(fā)出的標(biāo)準(zhǔn)網(wǎng)站,不但價格便宜而且實用、靈活,特別適合中小公司網(wǎng)站制作。網(wǎng)站管理系統(tǒng)簡單易用,維護(hù)方便,您可以完全操作網(wǎng)站資料,是中小公司快速網(wǎng)站建設(shè)的選擇。

  
 
  1. List list = new ArrayList(); list.add(1);   //把一個整數(shù)加入到集合中
  2. int i = list.get(0);    //從集合中取出元素

  ArrayList用起來是多么的順手!當(dāng)時我只知道尖括號<>里面只能加入大寫字母開頭的Object類型,不能加入int、char、double這些原始類型,至于原因沒研究過,這么規(guī)定就這么用唄。

  但是隨著對“碼農(nóng)”式無腦學(xué)習(xí)法的逐漸厭倦,我開始重新審視Java代碼內(nèi)部的東西。

  首當(dāng)其沖的就是每個項目一定用到的ArrayList。在我的另一篇博客中已經(jīng)對ArrayList的源碼實現(xiàn)做了大體的分析。然而還有幾個源碼中看不出來,但是確實存在疑點的問題亟待解決。

 
 
  1. List list = new ArrayList();

這句代碼中每個元素是Integer類型,那么往list里面add新元素的時候必須為Integer,比如加個String進(jìn)去,代碼下面就會出現(xiàn)紅色波浪線。
但是這句list.add(1) 眾所周知,代碼里面隨便寫個不帶小數(shù)點的數(shù)字,那它就是個int;把一個int加到一個只能有Integer的List中不報錯,不覺得有貓膩嗎?

同樣地,int i = list.get(0),取出list中索引為0的元素,也應(yīng)該是個Integer,為什么接收的變量就是個int呢?這是一個多么明顯的類型不匹配錯誤??!

以前,我確實聽說過“包裝類”這個概念,但是忽視了它,因為我一直覺得Integer,F(xiàn)loat這些東西,說難聽點就是擺出來裝裝逼的,只是因為List不接受int,float類型,迫不得已發(fā)明了Integer,Float,實際并沒有卵用。

最近看了《Effective Java》里面的一節(jié),名字叫“Prefer primitive types to boxed primitives”。里面羅列了很多原始類型和包裝類型混用的例子,搞得我暈頭轉(zhuǎn)向的。下面是其中一段代碼:

  
 
  1. Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) {      sum += i;   } System.out.println(sum);

據(jù)書中講,這是一段運行效率低到不可救藥的代碼,你能看出其中的問題嗎?
反正我當(dāng)時看到這段代碼就明顯感覺到,Java對于原始類型與相應(yīng)的Object類型的轉(zhuǎn)化,在編譯過程中肯定做了什么見不得人的事情……

下面正式引出本文的話題:AutoBoxing and Unboxing(自動裝箱&自動拆箱)

看一個最簡單的例子:

  
 
  1. Character ch = 'a';  //Character是char的包裝類

這里沒有出現(xiàn)任何錯誤,其實編譯器在代碼優(yōu)化的時候,暗中轉(zhuǎn)化成了下面的代碼:

  
 
  1. Character ch = Character.valueOf('a'); 

這就是說,"="右側(cè)自動調(diào)用Character類對應(yīng)的靜態(tài)方法構(gòu)造出了一個Character的實例。
為了進(jìn)一步說明,這里稍微看一下valueOf方法

  
 
  1. public static Character valueOf(char c) {         return c < 128 ? SMALL_VALUES[c] : new Character(c);     }   //如果字符在緩沖區(qū)中,直接取出Character實例,否則要重新構(gòu)造
  2.    private static final Character[] SMALL_VALUES = new Character[128];  //類中自帶一個靜態(tài)的緩沖區(qū),保存128個常用ASCII碼字符對應(yīng)的Character實例,免去每次重新構(gòu)造實例的麻煩
  3.    static {         for (int i = 0; i < 128; i++) {             SMALL_VALUES[i] = new Character((char) i);  //調(diào)用構(gòu)造函數(shù)
  4.        }     }

對于Integer等其他包裝類,自身都帶有一個靜態(tài)的valueOf方法。每次編譯器檢查到需要把一個int傳給Integer時,就自動對代碼進(jìn)行轉(zhuǎn)化。
比如上面的list.add(1),在編譯過程中編譯器發(fā)現(xiàn)要傳進(jìn)去的參數(shù)是int,但是要接收的是Integer,于是代碼變?yōu)椋?/p>

 
 
  1. list.add(Integer.valueOf(1));

以上就是自動裝箱(auto-boxing)的過程。

自動裝箱一般在兩種情況下會發(fā)生(以int和Integer為例):
1、把int作為一個方法的參數(shù)傳進(jìn)來,但是方法體里面希望得到的參數(shù)是Integer;
2、在賦值過程中,"="左邊是Integer變量,右邊是int變量。

這樣一來,自動拆箱的過程就順理成章了??匆韵麓a:

  
 
  1. public static int sumEven(List li) {     int sum = 0;     for (Integer i: li)         if (i % 2 == 0)             sum += i;         return sum; }

在循環(huán)體內(nèi)做了兩次拆箱操作,編譯器會轉(zhuǎn)換成以下代碼:

  
 
  1. public static int sumEven(List li) {     int sum = 0;     for (Integer i: li)         if (i.intValue() % 2 == 0)             sum += i.intValue();         return sum; }

Integer的intValue方法就簡單多了,直接返回被包裝的int值

  
 
  1. @Override     public int intValue() {         return value;    //value是Integer的成員變量 
  2. }

自動拆箱的用處跟自動裝箱正好相反,也是用在參數(shù)傳遞和賦值過程中,這里就不贅述了。
我們再來分析一下那段超級低效的代碼吧,經(jīng)過自動拆裝箱轉(zhuǎn)換之后應(yīng)該是這樣子的:

  
 
  1. Long sum = Long.valueOf(0L); for (long i = 0; i < Integer.MAX_VALUE; i++) {      sum = Long.valueOf(sum.longValue() + i);   //低效所在
  2. } System.out.println(sum.toString());

在循環(huán)體里面,簡簡單單只有一句話,竟然包含一次拆箱和一次裝箱操作,在經(jīng)過20多億次的循環(huán)之后,效率損耗得難以置信!
既然拆箱和裝箱可以看做“逆運算”,那么為什么還要進(jìn)行多余的操作呢?直接用原始值運算,然后一次裝箱不是更省事嗎

 
 
  1. Long sum = 0L; long s = sum; for (long i = 0; i < Integer.MAX_VALUE; i++) {      s += i;   } sum = Long.valueOf(s); System.out.println(sum);

參考資料:https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html


當(dāng)前標(biāo)題:Java暗箱操作之自動裝箱與拆箱
網(wǎng)頁地址:http://m.5511xx.com/article/cdjojsc.html