考虑过我在为Android创建的其中一个应用程序中不得不重复从int转换为String。我坐下来写了一个小实用程序类,我认为这样可以减轻由于Integer.toString()等函数调用而无法看到的潜伏变量的分配......
private int[] iMods = {
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000};
private int tmpInt = 0;
private int MAX_DIGITS = 6;
private char[] cScoreDigit = new char[MAX_DIGITS];
private int[] iScoreDigit = new int[MAX_DIGITS];
private StringBuilder mScoreStringBuilder = new StringBuilder("000000");
public String intToString(final int pInt, final int pMAX_DIGITS){
MAX_DIGITS = pMAX_DIGITS;
for (tmpInt = 1; tmpInt <= MAX_DIGITS; tmpInt++){ // Set each cScoreDigit to proper equivalent of iScoreDigit without cast!
switch ((pInt % iMods[tmpInt]) / iMods[tmpInt - 1]){
case 0:
cScoreDigit[MAX_DIGITS - tmpInt] = '0';
break;
case 1:
cScoreDigit[MAX_DIGITS - tmpInt] = '1';
break;
case 2:
cScoreDigit[MAX_DIGITS - tmpInt] = '2';
break;
case 3:
cScoreDigit[MAX_DIGITS - tmpInt] = '3';
break;
case 4:
cScoreDigit[MAX_DIGITS - tmpInt] = '4';
break;
case 5:
cScoreDigit[MAX_DIGITS - tmpInt] = '5';
break;
case 6:
cScoreDigit[MAX_DIGITS - tmpInt] = '6';
break;
case 7:
cScoreDigit[MAX_DIGITS - tmpInt] = '7';
break;
case 8:
cScoreDigit[MAX_DIGITS - tmpInt] = '8';
break;
case 9:
cScoreDigit[MAX_DIGITS - tmpInt] = '9';
}
}
// Delete all 0's
mScoreStringBuilder.delete(0, mScoreStringBuilder.length());
return mScoreStringBuilder.append(cScoreDigit).toString();
}
现在我只是好奇A)这是否真的是这样做的正确方法,以及B)这样的事情是否值得研究,因为每一步都有额外的数学运算?似乎反效果,但至少会限制GC运行正确吗?提前谢谢!
[编辑]
我注意到StringBuilder.toString()实际上会分配一个临时对象,这正是我试图避免的。没有分配的任何其他方式简单地从char []转换为String?或者如下所述,这对于String类是不可能的?
答案 0 :(得分:2)
不,最后的toString创建一个新的String(如果你愿意,请检查代码,java库源都可用)。
由于字符串是不可变的,因此您无法避免分配,因为您返回了一个字符串。
如果您返回用于构建数字的字符串构建器,并在下次调用时重复使用它,并且永远不会将其转换为字符串,您可以正常使用,但第二次将其转换为字符串(无论如何)你是怎么做的)你正在分配内存。
要做到这一点,你的方法要么必须接受传入的可变对象(StringBuilder或char数组),要么必须重用静态对象(使其成为单线程)
我尝试了一次,它总是归结为在某种程度上将它转换为字符串,取消所有工作,并使它比你刚刚使用显而易见的方式更慢。
还要记住,在Java中,短期内存分配并不像你想象的那么糟糕 - 它们在性能方面更像是C中的堆栈分配。
我所做的研究和测试表明,你可以做的一件事是避免在循环中连接字符串 - 其他一切(包括一次性字符串连接)最简单的代码将比你能做的任何事情都快或快想出来。