我在使用BlackBerry JDE 6.0时遇到问题以下代码向我发出警告(并在运行时导致错误)
String s = "hello";
doSomeStuff(s + "world");
警告:
Warning!: Reference to undefined class: java.lang.StringBuilder
我不使用任何StringBuilder。我搜索并发现最新版本的RIM API不包含StringBuilder类。
将JRE版本更改为1.4可能有所帮助,但它给我带来了很大麻烦,因为我无法在此版本中使用泛型集合和一些新的apis。
另一个解决方案是我可以使用 StringBuffer ,但我不能简单地使用'+'运算符吗?为什么难以尝试?
的更新:
我正在寻找使用'+'运算符的另一种方法,因为我的代码已经使用了很多,我不想花很多时间来替换所有这些。
答案 0 :(得分:5)
Java编译器将使用一系列字符串连接自动转换任何表达式以使用缓冲区。在Java 1.5之前,只有一个选择 - StringBuffer。然而,它在早期的Java中遇到了同步所有公共方法的惯例。在Java 1.5中添加了一个新的缓冲类 - StringBuilder - 它更好,因为它会丢弃同步,让它由类的用户来正确地同步访问。当Java编译器以Java 1.5或更高版本为目标时,它将使用StringBuilder。对于1.5之前的版本,它将使用StringBuffer。
BlackBerry设备使用基于Java 1.3的Java-ME,因此不存在StringBuilder类。您的问题是您正在编写现代Java-SE代码并希望将其部署在Java-ME BlackBerry设备上。如果您使用的是Eclipse,请将Java语言合规性级别更改为1.3。这将使编译器正确生成StringBuffer引用。它还将使用泛型语法错误。这是BlackBerry开发的预期 - 你不会得到泛型。
示例代码:
public class test {
public static String concat(String a, String b) {
return a + b;
}
}
使用javac -source 1.5 -target 1.5 test.java
public static java.lang.String concat(java.lang.String, java.lang.String);
Code:
0: new #2; //class java/lang/StringBuilder
3: dup
4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_1
12: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn
使用javac -source 1.3 -target 1.3 test.java
public static java.lang.String concat(java.lang.String, java.lang.String);
Code:
0: new #2; //class java/lang/StringBuffer
3: dup
4: invokespecial #3; //Method java/lang/StringBuffer."<init>":()V
7: aload_0
8: invokevirtual #4; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
11: aload_1
12: invokevirtual #4; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
15: invokevirtual #5; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
18: areturn
答案 1 :(得分:0)
使用+运算符追加字符串时,将隐式使用StringBuilders。因为字符串是不可变的,所以重复附加是O(n ^ 2)操作。解决方案是StringBuilders,它具有分摊的O(n)附加时间,并且只要在字符串和其他内容上使用+运算符时就会隐式使用。该代码正在内部扩展到:
doSomeStuff(new StringBuilder().append(s).append("world").toString());
您应该能够通过以下方式解决这个问题:
doSomeStuff(s.append("world"));
但是,因为这会影响StringBuilders要解决的问题,请考虑回到其他人建议的StringBuffer实现。
您可以尝试编写自己的包装StringBuffer的StringBuilder类。我认为你需要公开的唯一方法是一堆append(?)s(一个用于每个基本类型,一个用于String,一个用于Object调用对象toString并回退到String一个)和一个toString ()。我不知道这是否有效,这取决于编译器生成的代码是否使用StringBuilder的完全限定名称。但它可能值得一试。除此之外我不能想到任何其他方法可以使它工作,除了你可以找到一个开关,当你使用+运算符时,它会关闭使用StringBuilders生成代码。
您可以尝试以下方式:
class StringBuilder
{
StringBuffer buf = null;
public StringBuilder()
{
buf = new StringBuffer();
}
public StringBuilder append(StringBuilder other)
{
buf.append(other.buf);
return this;
}
public StringBuilder append(String s)
{
buf.append(s);
return this;
}
public StringBuilder append(Object o)
{
buf.append(o.toString());
return this;
}
public StringBuilder append(int i)
{
buf.append(i);
return this;
}
/* SNIP: append() methods for every other primitive type */
public String toString()
{
return buf.toString();
}
}
说实话,我不知道这是否会奏效,但值得一试。
答案 2 :(得分:0)
您使用的编译器版本是什么?
据我所知,至少从版本1.5开始,在编译期间,运算符+被StringBuilder替换,在某些情况下。例如:
当代码中出现“静态”字符串连接时:String s = "hello" + "world";
但是,当在编译时无法确定连接结果时,它将无法转换为StringBuilder。
编写完所有上述内容后,我建议不要依赖编译器优化技术,并建议您使用StringBuilder作为良好实践。
如果您有编译问题,您应该尝试显式使用StringBuffer,或者进一步减少编译器版本
另请参阅此处的一些optimizations建议。