成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java暗箱操作之自動裝箱與拆箱

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

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

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

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

[[147738]]

  但是隨著對“碼農”式無腦學習法的逐漸厭倦,我開始重新審視Java代碼內部的東西。

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

  1. List<Integer> list = new ArrayList<Integer>(); 

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

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

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

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

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

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

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

看一個最簡單的例子:

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

這里沒有出現任何錯誤,其實編譯器在代碼優化的時候,暗中轉化成了下面的代碼:

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

這就是說,"="右側自動調用Character類對應的靜態方法構造出了一個Character的實例。
為了進一步說明,這里稍微看一下valueOf方法

 

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

 

對于Integer等其他包裝類,自身都帶有一個靜態的valueOf方法。每次編譯器檢查到需要把一個int傳給Integer時,就自動對代碼進行轉化。
比如上面的list.add(1),在編譯過程中編譯器發現要傳進去的參數是int,但是要接收的是Integer,于是代碼變為:

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

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

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

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

 

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

 

在循環體內做了兩次拆箱操作,編譯器會轉換成以下代碼:

 

  1. public static int sumEven(List<Integer> 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. }
自動拆箱的用處跟自動裝箱正好相反,也是用在參數傳遞和賦值過程中,這里就不贅述了。
我們再來分析一下那段超級低效的代碼吧,經過自動拆裝箱轉換之后應該是這樣子的:

  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()); 

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

  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

 

 

 

責任編輯:王雪燕 來源: 博客園
相關推薦

2020-11-02 13:06:42

Java裝箱拆箱

2012-03-26 11:32:45

Java

2009-08-26 03:39:00

C#裝箱和拆箱

2021-09-06 14:30:34

C#裝箱拆箱

2009-08-28 11:22:11

C#裝箱和拆箱

2009-08-06 15:40:11

C#裝箱和拆箱

2009-09-01 17:51:47

C#拆箱C#裝箱

2009-10-22 19:11:25

CLR Via C#教

2021-02-28 21:47:51

Java語法糖算數

2019-10-30 16:03:48

JavaJava虛擬機數據庫

2018-09-05 15:51:25

Java自動拆裝箱

2015-09-28 08:46:19

Java自動裝箱性能

2009-07-07 17:56:00

JDK1.5封箱及拆箱

2009-08-11 15:17:12

C#基礎知識

2010-05-04 08:58:02

.NET

2023-09-07 08:05:32

三元表達式自動

2010-11-11 11:19:19

騰訊

2025-04-28 03:22:00

2009-08-11 14:20:41

C# .NET學習經驗

2021-12-20 22:58:23

手機內存技術
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 天天爽夜夜爽精品视频婷婷 | 亚洲精品一区国语对白 | 日韩图区 | 91成人精品 | 国产一区二区影院 | 在线免费看黄 | 国产成人一区 | 国产在线视频一区二区董小宛性色 | 久久一区视频 | 在线播放国产一区二区三区 | 中文字幕高清在线 | 天堂中文资源在线 | 日韩在线一区二区三区 | 四虎成人精品永久免费av九九 | 日韩三级在线观看 | jlzzjlzz欧美大全 | 久久久免费在线观看 | 一区二区在线 | 成人免费视频网址 | 国产黄色大片在线免费观看 | 久草新在线 | 日韩精品免费看 | 午夜小视频在线观看 | 久久久久久久一区二区三区 | 国产精品欧美一区二区三区不卡 | 午夜精品久久久久久久星辰影院 | 国产精品久久久久久久午夜片 | 青青草av | 成人精品国产免费网站 | 人妖av| 久久网一区二区三区 | 午夜免费在线电影 | 黄频视频 | 久久午夜影院 | 亚洲成人久久久 | 国产区高清 | 国产精品一区二区无线 | 日韩成人 | 日韩一二区在线观看 | 一区二区亚洲 | 日韩网站在线 |