感谢@izht提供源代码的链接。我已找到有关此问题的错误。
仅当String的后备数组具有与实际String不同(更长)的值时,才会发生这种情况。特别是
String.offset(私有变量)大于零时。
解决方法是:
public String replace(CharSequence target, CharSequence replacement) { if (target == null) { throw new NullPointerException("target == null"); } if (replacement == null) { throw new NullPointerException("replacement == null"); } String targetString = target.toString(); int matchStart = indexOf(targetString, 0); if (matchStart == -1) { // If there's nothing to replace, return the original string untouched. return this; } String replacementString = replacement.toString(); // The empty target matches at the start and end and between each character. int targetLength = targetString.length(); if (targetLength == 0) { int resultLength = (count + 2) * replacementString.length(); StringBuilder result = new StringBuilder(resultLength); result.append(replacementString);// for (int i = offset; i < count; ++i) { // original, bug for (int i = offset; i < (count + offset); ++i) { // fix result.append(value[i]); result.append(replacementString); } return result.toString(); } StringBuilder result = new StringBuilder(count); int searchStart = 0; do { // Copy characters before the match... result.append(value, offset + searchStart, matchStart - searchStart); // Insert the replacement... result.append(replacementString); // And skip over the match... searchStart = matchStart + targetLength; } while ((matchStart = indexOf(targetString, searchStart)) != -1); // Copy any trailing chars... result.append(value, offset + searchStart, count - searchStart); return result.toString();}
我不确定为什么Android必须以
replace()这种方式更改(并错误地更改)。原始的Java实现没有此问题。
顺便说一下, 现在是什么? 我该怎么办?(除了
replace()格外小心使用,或丢弃我的Android手机:-/)
顺便说一句,我很确定我的LG E720 Optimus Chic(Android
2.2)使用的源代码与此不同。在目标字符串
String.replace()为
空的情况下, 它会继续停止(可疑无限循环)。最近我发现它抛出此错误消息:
05-10 16:41:13.155: E/AndroidRuntime(9384): FATAL EXCEPTION: main05-10 16:41:13.155: E/AndroidRuntime(9384): java.lang.OutOfMemoryError05-10 16:41:13.155: E/AndroidRuntime(9384): at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:97)05-10 16:41:13.155: E/AndroidRuntime(9384): at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:157)05-10 16:41:13.155: E/AndroidRuntime(9384): at java.lang.StringBuilder.append(StringBuilder.java:217)05-10 16:41:13.155: E/AndroidRuntime(9384): at java.lang.String.replace(String.java:1497)05-10 16:41:13.155: E/AndroidRuntime(9384): at com.example.testprojectnew.MainActivity.onCreate(MainActivity.java:22)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.app.Instrumentation.callActivityonCreate(Instrumentation.java:1047)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.app.ActivityThread.access00(ActivityThread.java:125)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.os.Handler.dispatchMessage(Handler.java:99)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.os.Looper.loop(Looper.java:123)05-10 16:41:13.155: E/AndroidRuntime(9384): at android.app.ActivityThread.main(ActivityThread.java:4627)05-10 16:41:13.155: E/AndroidRuntime(9384): at java.lang.reflect.Method.invokeNative(Native Method)05-10 16:41:13.155: E/AndroidRuntime(9384): at java.lang.reflect.Method.invoke(Method.java:521)05-10 16:41:13.155: E/AndroidRuntime(9384): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)05-10 16:41:13.155: E/AndroidRuntime(9384): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)05-10 16:41:13.155: E/AndroidRuntime(9384): at dalvik.system.NativeStart.main(Native Method)
仔细考虑一下,如果那个for循环的东西 是 bug。这应该是一个编译时问题。为什么在不同的手机(不同版本的Android)中,它的行为会有所不同?
完整的解决方法
获得了 Google
的更新,他们已经对其进行了修补,并将在以后的版本中进行更正。
同时,我根据他们的代码编写了一个修补方法:
(这是必要的,因为(1)我们仍然必须等待正确的发布,(2)我们需要照顾没有进行该固定更新的设备)
public static String replacePatched(final String string, final CharSequence target, final CharSequence replacement) { if (target == null) { throw new NullPointerException("target == null"); } if (replacement == null) { throw new NullPointerException("replacement == null"); } final String targetString = target.toString(); int matchStart = string.indexOf(targetString, 0); if (matchStart == -1) { // If there's nothing to replace, return the original string untouched. return new String(string); } final char[] value = string.toCharArray(); // required in patch final int count = value.length; // required in patch final String replacementString = replacement.toString(); // The empty target matches at the start and end and between each character. if (targetString.length() == 0) { // The result contains the original 'count' characters, a copy of the // replacement string before every one of those characters, and a final // copy of the replacement string at the end. final StringBuilder result = new StringBuilder(count + (count + 1) * replacementString.length()); result.append(replacementString); for (int i = 0; i < count; ++i) { result.append(value[i]); result.append(replacementString); } return new String(result); // StringBuilder.toString() does not give exact length } final StringBuilder result = new StringBuilder(count); int searchStart = 0; do { // Copy characters before the match... result.append(value, searchStart, matchStart - searchStart); // Insert the replacement... result.append(replacementString); // And skip over the match... searchStart = matchStart + targetString.length(); } while ((matchStart = string.indexOf(targetString, searchStart)) != -1); // Copy any trailing chars... result.append(value, searchStart, count - searchStart); return new String(result); // StringBuilder.toString() does not give exact length}
详细版本:
public static String replacePatched(final String string, final CharSequence target, final CharSequence replacement) { if (target == null) { throw new NullPointerException("target == null"); } if (replacement == null) { throw new NullPointerException("replacement == null"); }// String targetString = target.toString(); // original final String targetString = target.toString();// int matchStart = indexOf(targetString, 0); // original int matchStart = string.indexOf(targetString, 0); if (matchStart == -1) { // If there's nothing to replace, return the original string untouched.// return this; // original return new String(string); } final char[] value = string.toCharArray(); // required in patch final int count = value.length; // required in patch// String replacementString = replacement.toString(); // original final String replacementString = replacement.toString(); // The empty target matches at the start and end and between each character.// int targetLength = targetString.length(); // original// if (targetLength == 0) { // original if (targetString.length() == 0) {// int resultLength = (count + 2) * replacementString.length(); // original// // The result contains the original 'count' characters, a copy of the// // replacement string before every one of those characters, and a final// // copy of the replacement string at the end.// int resultLength = count + (count + 1) * replacementString.length(); // patched by Google Android// StringBuilder result = new StringBuilder(resultLength); // original final StringBuilder result = new StringBuilder(count + (count + 1) * replacementString.length()); result.append(replacementString);// for (int i = offset; i < count; ++i) { // original// int end = offset + count; // patched by Google Android// for (int i = offset; i != end; ++i) { // patched by Google Android for (int i = 0; i < count; ++i) { result.append(value[i]); result.append(replacementString); }// return result.toString(); // original return new String(result); // StringBuilder.toString() does not give exact length }// StringBuilder result = new StringBuilder(count); // original final StringBuilder result = new StringBuilder(count); int searchStart = 0; do { // Copy characters before the match...// result.append(value, offset + searchStart, matchStart - searchStart); // original result.append(value, searchStart, matchStart - searchStart); // Insert the replacement... result.append(replacementString); // And skip over the match...// searchStart = matchStart + targetLength; // original searchStart = matchStart + targetString.length();// } while ((matchStart = indexOf(targetString, searchStart)) != -1); // original } while ((matchStart = string.indexOf(targetString, searchStart)) != -1); // Copy any trailing chars...// result.append(value, offset + searchStart, count - searchStart); // original result.append(value, searchStart, count - searchStart);// return result.toString(); // original return new String(result); // StringBuilder.toString() does not give exact length}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)