在java中,大家肯定都會遇到int類型轉String類型的情形,知其然知其所以然,總結加分析一下,int類型轉String類型有以下幾種方式:
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+"" = 257
E/time: String.valueOf(a) = 140
E/time: Integer.toString(a) = 159
可以看到在效率上除了a+”“這種方式之外,其他兩種方式的效率差不多,為什么呢?看源碼!
先看看后兩種方式的源碼: String.valueOf(a)->Integer.toString(a)->IntegralToString.intToString(a)->convertInt(null, a)
Integer.toString(a)->IntegralToString.intToString(a)->convertInt(null, a)
可以看到String.valueOf是通過調用Integer.toString實現的,也難怪他們的效率如此接近。他們最后都會調用到convertInt函數中:
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);
}
}
分析一下,這個函數的工作主要可以分為這幾步:
// 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[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的長度,都是用來處理0~99這100個數字,個位和十位的處理方式也很清楚。
從代碼角度來看,這個算法在數字小於100的和大於100的處理方式是不一樣的,小於100的快速計算法執行時間會遠遠短於大於100的方式,驗證一下,將a變量修改為10:
E/time: i+"" = 199
E/time: String.valueOf() = 7
E/time: Integer.toString() = 6
確實短了很多!!!
再來看看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.
地址:http://docs.oracle.com/javase/6/docs/api/java/lang/String.html
可以看到,’+’運算符的主要方式是使用StringBuilder或者StringBuffer來實現的,類似於:
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append(i);
String strI = sb.toString();
再來看看append的源碼: StringBuffer.append->IntegralToString.appendInt(this, a)->convertInt(sb, i)
可以看到’+’運算符最后也是調用到了同一個函數,只不過第一個參數的sb不為null而已,所以已經很清楚了,’+’運算符的執行效率不高的原因應該就在之前的new StringBuilder等操作和之后的StringBuilder.toString等操作,反編譯class文件也可以得出一樣的結論:
http://stackoverflow.com/a/4105406。
所以a+”“的方式以后就少用一點了,效率不高,也顯得不太專業。
String 擴展的相關知識:
常量池的內存分配在 JDK6、7、8中有不同的實現:
1. JDK6及之前版本中,常量池的內存在永久代PermGen進行分配,所以常量池會受到PermGen內存大小的限制。
2. JDK7中,常量池的內存在Java堆上進行分配,意味着常量池不受固定大小的限制了。
3. JDK8中,虛擬機團隊移除了永久代PermGen。
關於永久代移除:http://www.infoq.com/cn/articles/Java-PERMGEN-Removed
例子1:
public class StringTest {
public static void main(String[] args) {
String a = "java";
String b = "java";
String c = "ja" + "va";
}
}
變量 a、b 和 c 都指向常量池的 “java” 字符串,表達式 “ja” + “va” 在編譯期間會把結果值”java”直接賦值給c,所以最終的結果 a==c 為 true。
例子2:
public class StringTest {
public static void main(String[] args) {
String a = "hello ";
String b = "world";
String c = a + b;
String d = "hello world";
}
}
我們根據上面知道在 java 中 “+” 運算符實際上是使用 StringBuilder.append 去實現的,所以此時會在 Java 堆上新建一個 String 對象,這個 String 對象最終指向常量池的 “hello world”,所以說此時 c==d 為 false。
不過有種特殊情況,當final修飾的變量發生連接動作時,編譯器會進行優化,將表達式結果直接賦值給目標變量:
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";
}
}
所以此時 c==d 為 true。
http://www.importnew.com/21711.html
http://www.importnew.com/21720.html
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。