摘要:最近算是比較深入的了解了一下的源碼,就想著寫點東西記錄一下,一來可以加深理解,再來也算是為我刷了那么久平臺貢獻一點自己的綿薄之力。這兩個方法都是給當前的實例的屬性賦值,參數為類型的構造器直接將參數賦值給屬性,參數為是將方法的返回值賦值。
最近算是比較深入的了解了一下Integer的源碼,就想著寫點東西記錄一下,一來可以加深理解,再來也算是為我刷了那么久segmentfault平臺貢獻一點自己的綿薄之力。
一、構造函數:
解讀一個類的源碼我喜歡從構造函數入手,這里先上Integer的構造源碼:
public Integer(int value) { this.value = value; } public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); }
在Integer類中提供了兩個構造函數,分別針對構造參數為基本類型int和引用類型String。這兩個方法都是給當前的實例的value屬性賦值,參數為int類型的構造器直接將參數賦值給value屬性,參數為String是將parseInt(String s, int radix)方法的返回值賦值。JDK1.5之后,java提供了自動裝箱和自動拆箱的功能。自動裝箱也就是調用了Integer類的一個靜態方法valueOf方法,先看源碼:
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
源碼中有一個IntegerCache,這一個私有的內部類。這個類緩存了low - high之間數字的包裝類。關于這個類的分析在下面,反正你需要記住它把一些數字的包裝類提前緩存了,如果判斷成立就把緩存中的那個包裝類返回,如果不則new一個新的。這里也就明白了下面問題的原因了:
Integer a = 100; Integer b = 100; Integer c = 200; Integer d = 200; System.out.println(a == b);//true System.out.println(c == d);//false
通過javap -c/javap -verbose 命令可以查看字節碼;紅色圈圈里就是我們jdk5之后的基本類型的自動包裝的字節碼實現,可以看出,此處是調用了Integer.valueOf(..)方法的:說白了就是Integer a = 100 等價于Integer a = Integer.valueOf(100)
二、IntegerCache:
先上源碼:
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
以上可以知道這個類是私有的且是靜態的,并且他有三個被final修飾的靜態filed外加一個靜態塊和一個私有的構造器;很簡單很普通的一個類,被緩存的包裝類就介于low - high之間,low的值已經寫死-128,而high的值由你的虛擬機決定sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"),既然是一個參數也就意味著你可以動態設置,具體怎么設置自行百度。然后在循環中將low - high之間數字的裝箱后方法cache[]這個Integer類型的數組中。這樣就完成了緩存。
三、toString(int i): 照例先上源碼:
public static String toString(int i) { if (i == Integer.MIN_VALUE) return "-2147483648"; int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); char[] buf = new char[size]; getChars(i, size, buf); return new String(buf, true); }
這個方法內部調用了兩個方法:stringSize和getChars,toString方法的實現也就是由這兩個方法合作完成,stringSize實現上很是比較簡單的,源碼我就不上了,它是用來計算參數i的位數也就是轉成字符串之后的字符串的長度。內部結合一個已經初始化好的int類型的數組sizeTable來完成這個計算。稍動頭腦就能想明白,很巧妙的一個方法。然后來說說toString這個方法實現的最大功臣getChars這個方法,上源碼:
static void getChars(int i, int index, char[] buf) { int q, r; int charPos = index; char sign = 0; if (i < 0) { sign = "-"; i = -i; } // Generate two digits per iteration while (i >= 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q << 6) + (q << 5) + (q << 2)); i = q; buf [--charPos] = DigitOnes[r]; buf [--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i <= 65536, i); for (;;) { q = (i * 52429) >>> (16+3); r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... buf [--charPos] = digits [r]; i = q; if (i == 0) break; } if (sign != 0) { buf [--charPos] = sign; } }
三個參數:i:被初始化的數字,index:這個數字的長度(包含了負數的符號“-”),buf:字符串的容器-一個char型數組。第一個if判斷,如果i<0,sign記下它的符號“-”,同時將i轉成整數。下面所有的操作也就只針對整數了,最后在判斷sign如果不等于零將sig你的值放在char數組的首位buf [--charPos] = sign;。 最后來分析方法中的兩個循環:while和for,其實這兩個循環做的事情一樣。只是while循環來處理i>65535的情況,且每次取兩位數:
buf [--charPos] = DigitOnes[r]; buf [--charPos] = DigitTens[r];
剩下的情況由for循環處理,且每次去一個數字。至于為什么這么做:// Fall thru to fast mode for smaller numbers,這是官方注釋,意思就是真對小的數字使用快速方式。針對這塊的理解我也是參考了知乎上的網友的回答java源碼中Integer.class中有個getChars方法,里面有個52429是怎么確定的? 表示感謝。
至此Integer類的核心也就完了。就這吧!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66067.html
摘要:本章部分內容從源碼中解讀一些自動裝箱與拆箱的原理,以及會出現的一些陷阱已經性能等。例題分析我們通過幾個經典的問題,來看看大家到底理解了裝箱與拆箱的知識點沒。 showImg(https://img-blog.csdnimg.cn/20190426221838971.gif);showImg(https://img-blog.csdnimg.cn/20190426221918208.pn...
每篇一句 胡適:多談些問題,少聊些主義 前言 Spring MVC和MyBatis作為當下最為流行的兩個框架,大家平時開發中都在用。如果你往深了一步去思考,你應該會有這樣的疑問: 在使用Spring MVC的時候,你即使不使用注解,只要參數名和請求參數的key對應上了,就能自動完成數值的封裝 在使用MyBatis(接口模式)時,接口方法向xml里的SQL語句傳參時,必須(當然不是100%的必須,...
摘要:估計這就是推薦使用的主要原因吧正負標識判斷輸入的字符串是否為開頭轉化邏輯字符串轉化為的關鍵在于數組,以進制為例,用表示到,滿才會進。 Integer的基本實現Integer的使用Integer封裝的操作 Integer的基本實現 基本描述:Integer是對原生基本類型int的封裝,其定義value來存儲值和一些用于描述int的信息 int value;//int int SIZE...
摘要:關于它的數據轉換使用了如下兩種機制隸屬于規范。這種類中的方法主要用于訪問私有的字段,且方法名符合某種命名規則。如果在兩個模塊之間傳遞信息,可以將信息封裝進中,這種對象稱為值對象,或。 每篇一句 千古以來要飯的沒有要早飯的,知道為什么嗎? 相關閱讀 【小家Spring】聊聊Spring中的數據轉換:Converter、ConversionService、TypeConverter、Pro...
摘要:重寫語言中的定義子類方法有一個方法與父類方法的名字相同且參數類型相同。父類方法的返回值可以替換掉子類方法的返回值。思維導圖參考文檔極客時間深入拆解虛擬機是如何執行方法調用的上廣告 原文 回顧Java語言中的重載與重寫,并且看看JVM是怎么處理它們的。 重載Overload 定義: 在同一個類中有多個方法,它們的名字相同,但是參數類型不同。 或者,父子類中,子類有一個方法與父類非私有方...
閱讀 1578·2021-10-14 09:42
閱讀 3818·2021-09-07 09:59
閱讀 1302·2019-08-30 15:55
閱讀 575·2019-08-30 11:17
閱讀 3341·2019-08-29 16:06
閱讀 505·2019-08-29 14:06
閱讀 3130·2019-08-28 18:14
閱讀 3649·2019-08-26 13:55