<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們平時應該都用過或者見過parseInt和valueOf這兩個方法。一般我們是想把String型別的字元數位轉成int型別。從這個功能層面來說,這兩個方法都一樣,都可以勝任這個功能。
但是,我們進入原始碼,看下Integer類下這兩個方法
public static int parseInt(String s) throws NumberFormatException { return parseInt(s,10); }
public static Integer valueOf(String s) throws NumberFormatException { return Integer.valueOf(parseInt(s, 10)); }
從程式碼,我們起碼看到了兩點:返回結果型別不一樣,parseInt方法返回的是int基本型別,valueOf方法返回的是Integer的包裝型別
valueOf方法實際上是呼叫了parseInt方法,也就是說,如果我們僅僅只需要得到字串型別字元數值對應的整數數值,那我們大可不必呼叫valueOf,因為這樣得到整形數值之後還要做一個裝箱的操作,將int封裝為Integer。
寫程式碼測試效率:
public class StringDemo { public static void main(String[] args) { // TODO Auto-generated method stub String str = "123"; long startTime = System.currentTimeMillis(); for(int i = 0;i<100000000;i++){ Integer.parseInt(str); } long endTime = System.currentTimeMillis(); System.out.println(endTime-startTime); } }
如下程式碼:
public class StringDemo { public static void main(String[] args) { // TODO Auto-generated method stub String str = "123"; long startTime = System.currentTimeMillis(); for(int i = 0;i<100000000;i++){ Integer.valueOf(str); } long endTime = System.currentTimeMillis(); System.out.println(endTime-startTime); } }
分別測試三遍,得到的時間如下,可以看到paraseInt()的效率更好。
方法 | 第一次時長 | 第二次時長 | 第三次時長 |
---|---|---|---|
parseInt() | 2946 | 2965 | 2952 |
valueOf() | 3124 | 3117 | 3126 |
我一直使用Integer的轉換,包括Long,列舉等,從來沒有注意它是怎麼實現的,最近有個業務組轉換報錯了,想看看是如何實現的。據筆者猜測:ASCII碼轉換?這是常用的計量,什麼大寫變小寫都是這樣實現的。下面看看如何實現的吧
public class StringParseInt { public static void main(String[] args) { String str = "-1234"; int i = Integer.parseInt(str); int y = Integer.valueOf(str); System.out.println(i + "t" + y); } }
輸出都正常,關鍵是看怎麼實現的
2.1 value of
public static Integer valueOf(String s) throws NumberFormatException { return Integer.valueOf(parseInt(s, 10)); }
本質還是parseInt,從這點看與parseInt沒有區別;但是這裡有裝箱,如果接收值是int建議直接使用parseInt,省去裝箱的過程。
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
如果在快取陣列,直接使用,看看快取陣列怎麼來的
private static class IntegerCache { //下限固定-128 static final int low = -128; //上限沒有初始化 static final int high; //核心快取陣列 static final Integer cache[]; //類載入初始化 static { // high value may be configured by property //初始127上限 int h = 127; //VM引數java.lang.Integer.IntegerCache.high可以設定Integer的最大上限 String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { //我沒設定的值,如果不是int字串型就會報錯,然後被捕獲 int i = parseInt(integerCacheHighPropValue); //取大,對比127;也就是至少是127 i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE // 上面官方註釋很明顯了,這裡減128再減1是因為low是-128 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; //建立快取陣列,如果設定java.lang.Integer.IntegerCache.high,不宜設定過大,過大很佔連續空間 cache = new Integer[(high - low) + 1]; int j = low; //初始化快取 for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) //斷言至少127,JLS7 assert IntegerCache.high >= 127; } private IntegerCache() {} }
從原始碼看Integer內部類裝載時,會初始化一個快取空間,儲存Integer物件。很多面試時就會被這個坑了,初始化的快取物件地址取值是一致的,可以使用==作對比;然後超過這個範圍的Integer就不能了,要使用Integer的eq方法
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
因為自動裝箱,實際上使用的value of方法,預設情況下,-128~127使用快取物件。
2.2 parseInt
/** * 這段註釋尤為重要,定義了符號位,定義了10進位制數位 * Parses the string argument as a signed decimal integer. The * characters in the string must all be decimal digits, except * that the first character may be an ASCII minus sign {@code '-'} * ({@code 'u005Cu002D'}) to indicate a negative value or an * ASCII plus sign {@code '+'} ({@code 'u005Cu002B'}) to * indicate a positive value. The resulting integer value is * returned, exactly as if the argument and the radix 10 were * given as arguments to the {@link #parseInt(java.lang.String, * int)} method. * * @param s a {@code String} containing the {@code int} * representation to be parsed * @return the integer value represented by the argument in decimal. * @exception NumberFormatException if the string does not contain a * parsable integer. */ public static int parseInt(String s) throws NumberFormatException { return parseInt(s,10); }
重點來哦,String能轉為int的本質,這裡需要傳一個核心引數,Integer給我們預設了10進位制,其他型別也是相同,比如Long
public static long parseLong(String s) throws NumberFormatException { return parseLong(s, 10); }
因為轉換後的就是10進位制的數位,可供使用。
進一步分析parseInt(String s, int radix);radix即進位制的意思。
public static int parseInt(String s, int radix) throws NumberFormatException { /* * WARNING: This method may be invoked early during VM initialization * before IntegerCache is initialized. Care must be taken to not use * the valueOf method. */ //字串不能為null,沒有判斷空字串 if (s == null) { throw new NumberFormatException("null"); } //進位制不能小於2,至少要2進位制 if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); } //進位制不能大於36 if (radix > Character.MAX_RADIX) { throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); } int result = 0; //正負標記,預設正 boolean negative = false; //字串長度 int i = 0, len = s.length(); int limit = -Integer.MAX_VALUE; int multmin; int digit; //幹活了 if (len > 0) { //首位字元 char firstChar = s.charAt(0); //這裡玩了個計謀,0字元的ASCII是48,後面的數位包括ABCDEF的ASCII都比0大; //其中 + 43; - 45 //只有帶符號位的會判斷,其他就預設正數 if (firstChar < '0') { // Possible leading "+" or "-" //負數 if (firstChar == '-') { negative = true; limit = Integer.MIN_VALUE; //非負即正,因為小於'0' } else if (firstChar != '+') throw NumberFormatException.forInputString(s); if (len == 1) // Cannot have lone "+" or "-" 註釋說明白了 throw NumberFormatException.forInputString(s); i++; } multmin = limit / radix; while (i < len) { // Accumulating negatively avoids surprises near MAX_VALUE // 拿到字元,轉換為ASCII數位並按進位制轉為數位 digit = Character.digit(s.charAt(i++),radix); //不能帶符號位,前面已經驗證了 if (digit < 0) { throw NumberFormatException.forInputString(s); } //最小限制,但是這裡是一個負數 if (result < multmin) { throw NumberFormatException.forInputString(s); } //由於是從高位向低位,所以需要進位制;字元每往後走,需要乘進位制 result *= radix; //同樣最小驗證,可能在某些地方有用,暫時沒看出來 if (result < limit + digit) { throw NumberFormatException.forInputString(s); } //這裡使用反向進位,為了照顧字元從前往後,也可以字元從後往前正向進位 result -= digit; } } else { throw NumberFormatException.forInputString(s); } //負數正數校正,上面的演演算法是反向進位 return negative ? result : -result; }
這裡說一下Character.digit(s.charAt(i++),radix)
public static int digit(char ch, int radix) { return digit((int)ch, radix); }
digit就是數位的意思,這裡直接把char字元強轉int型別,即ASCII數位,然後按照進位制轉換成相應的數位
小結:型別轉換其實是字元的ASCII的解析符號位,並按字元轉為數位,然後使用逆向負進位方式生成數位,最後修正符號得出我們想要的結果。演演算法符合了字串解析的順序,不符合人類的思維習慣。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45