0

我在使用 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 会有所帮助,但这给我带来了很大的麻烦,因为我无法在此版本中使用泛型集合和一些新的 api。
另一个解决方案是我可以使用StringBuffer,但我不能简单地使用 '+' 运算符吗?为什么很难尝试?
更新
我正在寻找另一种使用“+”运算符的方法,因为我的代码已经使用了其中的许多,我不想花很多时间来替换所有这些。

4

3 回答 3

5

Java 编译器会自动将任何带有一系列字符串连接的表达式转换为使用缓冲区。在 Java 1.5 之前,只有一种选择——StringBuffer。但是,它受到早期 Java 中同步所有公共方法的约定的影响。在 Java 1.5 中添加了一个新的缓冲区类 - StringBuilder - 这更好,因为它放弃了同步,让该类的用户正确同步访问。当 Java 编译器面向 Java 1.5 或更高版本时,它将使用 StringBuilder。对于 pre-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
于 2012-06-23T23:58:14.920 回答
0

当您使用 + 运算符附加字符串时,会隐式使用 StringBuilder。因为字符串是不可变的,所以重复追加是一个 O(n^2) 操作。解决方案是 StringBuilders,它摊销了 O(n) 附加时间,并且在您对字符串和其他内容使用 + 运算符时隐式使用。该代码正在内部扩展为:

doSomeStuff(new StringBuilder().append(s).append("world").toString());

您应该能够通过以下方式解决此问题:

doSomeStuff(s.append("world"));

但是,因为这又回到了 StringBuilders 打算解决的问题上,所以考虑回到其他人建议的 StringBuffer 实现。

您也许可以尝试编写自己的 StringBuilder 类来包装 StringBuffer。我认为您需要公开的唯一方法是一堆 append(?)s(每个原始类型一个,一个用于 String,一个用于调用对象 toString 并回退到 String 的 Object)和一个 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();
    }
}

老实说,我不知道这是否会奏效,但值得一试。

于 2012-06-20T04:34:57.940 回答
0

您使用的编译器版本是什么?
据我所知,至少从 1.5 版本开始,operator+ 在编译期间被 StringBuilder 替换,在某些情况下。例如:
当代码中存在这样的“静态”字符串连接时:String s = "hello" + "world";
但是,如果在编译时无法确定连接结果,则无法翻译为 StringBuilder。
写完以上所有内容后,我不建议依赖编译器优化技术,并且建议您使用 StringBuilder 作为良好实践。
如果你有编译问题,你应该尝试显式地使用 StringBuffer ,或者进一步降低编译器版本
参见这里的一些优化建议。

于 2012-06-20T04:35:53.163 回答