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 を使用できなかったため、大きな問題が発生しました。
もう 1 つの解決策は、 StringBufferを使用できることですが、単純に「+」演算子を使用することはできませんか? 挑戦しにくいのはなぜ?
更新:
「+」演算子を使用する別の方法を探しています。コードでそれらの多くを使用しており、それらすべてを置き換えるのに多くの時間を費やしたくないためです。

4

3 に答える 3

5

Java コンパイラは、一連の文字列連結を含む式を自動的に変換して、バッファを使用します。Java 1.5 より前は、StringBuffer という 1 つの選択肢しかありませんでした。ただし、すべてのパブリック メソッドを同期するという初期の 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
于 2012-06-23T23:58:14.920 に答える
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(?) (プリミティブ型ごとに 1 つ、文字列用に 1 つ、オブジェクト toString を呼び出して文字列にフォールバックするオブジェクト用に 1 つ) と 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 に答える