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