BlackBerry中的'+'字符串运算符和StringBuilder

时间:2012-06-20 04:25:10

标签: java blackberry stringbuilder

我在使用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 ,但我不能简单地使用'+'运算符吗?为什么难以尝试?
更新
我正在寻找使用'+'运算符的另一种方法,因为我的代码已经使用了很多,我不想花很多时间来替换所有这些。

3 个答案:

答案 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建议。