### [置頂] java int轉String所有方式的效率對比與深入解析

在java中，大家肯定都會遇到int類型轉String類型的情形，知其然知其所以然，總結加分析一下，int類型轉String類型有以下幾種方式：

1. a+”“
2. String.valueOf(a)
3. Integer.toString(a)
以上三種方法在實際使用過程中都是沒有問題的，但是效率上還是有些許差別的，所以寫個小程序來對比一下他們的效率：

``int a = 123456789;long start = System.currentTimeMillis();for (int i=0; i<100000; i++){    String m = a+"";}long end = System.currentTimeMillis();Log.e("time", "a+\"\" = " + (end - start));start = System.currentTimeMillis();for (int i=0; i<100000; i++){    String n = String.valueOf(a);}end = System.currentTimeMillis();Log.e("time", "String.valueOf(a) = " +(end-start));start = System.currentTimeMillis();for (int i=0; i<100000; i++){    String n = Integer.toString(a);}end = System.currentTimeMillis();Log.e("time", "Integer.toString(a) = " +(end-start));``

``E/time: a+"" = 257E/time: String.valueOf(a) = 140E/time: Integer.toString(a) = 159``

# String.valueOf(a) && Integer.toString(a)

先看看后兩種方式的源碼：
`String.valueOf(a)->Integer.toString(a)->IntegralToString.intToString(a)->convertInt(null, a)`

`Integer.toString(a)->IntegralToString.intToString(a)->convertInt(null, a)`

``private static String convertInt(AbstractStringBuilder sb, int i) {    boolean negative = false;    String quickResult = null;    if (i < 0) {        negative = true;        i = -i;        if (i < 100) {            if (i < 0) {                // If -n is still negative, n is Integer.MIN_VALUE                quickResult = "-2147483648";            } else {                quickResult = SMALL_NEGATIVE_VALUES[i];                if (quickResult == null) {                    SMALL_NEGATIVE_VALUES[i] = quickResult =                            i < 10 ? stringOf('-', ONES[i]) : stringOf('-', TENS[i], ONES[i]);                }            }        }    } else {        if (i < 100) {            quickResult = SMALL_NONNEGATIVE_VALUES[i];            if (quickResult == null) {                SMALL_NONNEGATIVE_VALUES[i] = quickResult =                        i < 10 ? stringOf(ONES[i]) : stringOf(TENS[i], ONES[i]);            }        }    }    if (quickResult != null) {        if (sb != null) {            sb.append0(quickResult);            return null;        }        return quickResult;    }    int bufLen = 11; // Max number of chars in result    char[] buf = (sb != null) ? BUFFER.get() : new char[bufLen];    int cursor = bufLen;    // Calculate digits two-at-a-time till remaining digits fit in 16 bits    while (i >= (1 << 16)) {        // Compute q = n/100 and r = n % 100 as per "Hacker's Delight" 10-8        int q = (int) ((0x51EB851FL * i) >>> 37);        int r = i - 100*q;        buf[--cursor] = ONES[r];        buf[--cursor] = TENS[r];        i = q;    }    // Calculate remaining digits one-at-a-time for performance    while (i != 0) {        // Compute q = n/10 and r = n % 10 as per "Hacker's Delight" 10-8        int q = (0xCCCD * i) >>> 19;        int r = i - 10*q;        buf[--cursor] = DIGITS[r];        i = q;    }    if (negative) {        buf[--cursor] = '-';    }    if (sb != null) {        sb.append0(buf, cursor, bufLen - cursor);        return null;    } else {        return new String(cursor, bufLen - cursor, buf);    }}``

1. 如果a為負數，將a變成正數，如果a還小於0，直接置為Integer.MIN_VALUE；如果a小於100，則直接使用TENS和ONES數組進行快速計算得出結果，加上’-‘號，直接返回該結果。
2. 如果a為正數並且小於100，直接使用TENS和ONES數組進行快速計算得出結果返回。
3. 如果上面兩步沒有處理完，說明a是大於100的數字，無法直接使用TENS和ONES數組進行快速計算，處理方式就是2位為一步循環處理，每次將這兩位使用TENS和ONES數組進行快速計算得出這兩位的結果存在數組的相應位置，直到只剩一位；最后剩下的一位使用DIGITS數組得出16進制的結果放在最后，返回結果。
那么問題來了，當a>=100的時候，那兩次while循環為什么會使用0x51EB851FL和0xCCCD這兩個數字呢？這個問題不要問我，我也不知道，不過源碼作者注釋寫的很明白了：
`// Compute q = n/100 and r = n % 100 as per "Hacker's Delight" 10-8`
`// Compute q = n/10 and r = n % 10 as per "Hacker's Delight" 10-8`

接着還有一個問題是TENS和ONES數組，直接看代碼，一目了然：

``/** TENS[i] contains the tens digit of the number i, 0 <= i <= 99. */private static final char[] TENS = {        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',        '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',        '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',        '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',        '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',        '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',        '9', '9', '9', '9', '9', '9', '9', '9', '9', '9'};/** Ones [i] contains the tens digit of the number i, 0 <= i <= 99. */private static final char[] ONES = {        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',};``

從代碼角度來看，這個算法在數字小於100的和大於100的處理方式是不一樣的，小於100的快速計算法執行時間會遠遠短於大於100的方式，驗證一下，將a變量修改為10：

``E/time: i+"" = 199E/time: String.valueOf() = 7E/time: Integer.toString() = 6``

# a+”“

再來看看a+”“的方式，我承認這種方式我用的最多了，因為太簡單了，java源碼對’+’運算符進行了重載，源碼我找不到啊，不過從網上找一些資料：

The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java. For additional information on string concatenation and conversion, see Gosling, Joy, and Steele, The Java Language Specification.

``StringBuilder sb = new StringBuilder();sb.append("");sb.append(i);String strI = sb.toString();``

`StringBuffer.append->IntegralToString.appendInt(this, a)->convertInt(sb, i)`

http://stackoverflow.com/a/4105406
所以a+”“的方式以后就少用一點了，效率不高，也顯得不太專業。

# 擴展

String 擴展的相關知識：

1. JDK6及之前版本中，常量池的內存在永久代PermGen進行分配，所以常量池會受到PermGen內存大小的限制。
2. JDK7中，常量池的內存在Java堆上進行分配，意味着常量池不受固定大小的限制了。
3. JDK8中，虛擬機團隊移除了永久代PermGen。

``public class StringTest {    public static void main(String[] args) {        String a = "java";        String b = "java";        String c = "ja" + "va";    }}``

``public class StringTest {    public static void main(String[] args) {        String a = "hello ";        String b = "world";        String c = a + b;        String d = "hello world";    }}``

``public class StringTest {    public static void main(String[] args) {        final String a = "hello ";        final String b = "world";        String c = a + b;        String d = "hello world";    }}``