1

重複の可能性:
+ が Java の文字列で機能するのはなぜですか?

次のステートメントは Java で有効です。

int a=50;
String tmp="a = ";
String b=tmp+a;

bタイプ String のa = 50(String として) が含まれるようになりました。

tmpString型でaあり、 型ですがint、連結が行われます (Java は演算子のオーバーロードをサポートしていませんが)。

Java が演算子のオーバーロードをサポートしていない理由の 1 つ (他の言語と同様。実際、私はどの言語についても深い知識がありません)。

Java は、演算子のオーバーロードをサポートしていません。演算子のオーバーロードは、C++ プログラムのあいまいさの原因となることがあり、Java 設計チームは、それが利点よりも問題を引き起こすと感じていました。

それについてもっと。

この発言はどうString b=tmp+a;評価される?演算子のオーバーロードと同等の概念が内部的に存在する必要があります。


1つだけ質問があります。それがどのように実装されているかを文字通り見ることができます?

StringBuilder/StringBufferこれを実現するために Java コンパイラが(メソッドを使用して) を使用していると聞いたことがありますが、append()それについてはわかりません。

4

3 に答える 3

5

技術的には、これはたまたま同じ記号を持つ別の演算子です。それは「文字列連結演算子」です。Java 言語仕様のセクション 15.18.1 を参照してください。

実装に関して、JLS は次のように述べています。

実装では、中間 Stringオブジェクトの作成と破棄を回避するために、変換と連結を 1 つのステップで実行することを選択できます。文字列連結の繰り返しのパフォーマンスを向上させるために、Java コンパイラはクラスまたは同様の手法を使用して、式の評価によって作成される中間オブジェクトStringBufferの数を減らすことができます。String

プリミティブ型の場合、実装では、プリミティブ型から文字列に直接変換することで、ラッパー オブジェクトの作成を最適化することもできます。

于 2012-07-21T16:10:50.527 に答える
2

Java では、ユーザー定義の演算子のオーバーロードは許可されていません。言語仕様は、必要な演算子を定義します:)

そして、はい、それが内部でどのように行われるかを見ることができます -javap -cクラスを逆アセンブルするために使用します。たとえば、私のマシンでは、コードは次のようにコンパイルされます。

   0: bipush        50
   2: istore_1
   3: ldc           #2    // String a =
   5: astore_2
   6: new           #3    // class java/lang/StringBuilder
   9: dup
  10: invokespecial #4    // Method java/lang/StringBuilder."<init>":()V
  13: aload_2
  14: invokevirtual #5    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  17: iload_1
  18: invokevirtual #6    // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  21: invokevirtual #7    // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  24: astore_3
  25: return

ただし、一部の詳細は実装固有です。特に、Sun/Oracle コンパイラは以前は を使用しStringBufferていましたが、利用可能な場合は使用StringBuilderするようになりました。

于 2012-07-21T16:12:06.420 に答える
-1

編集:この変更を行うコンパイラでさえ(私は知りませんでした)、文字列連結を使用すると、StringBuilderを使用するよりも遅くなります。(間違った =>いいえ、コンパイラは StringBuilder/StringBuffer を使用しません)。簡単なベンチマークを作成するだけでテストできます。+ 演算子は Java for Strings で「オーバーロード」されていますが、言語は演算子のオーバーロードをサポートしていません。

StringBuilder/StringBuffer をテストするには、次のようなことを試してください。

String str = "";
StringBuffer sbf = new StringBuffer();
StringBuilder sb = new StringBuilder();

int nTests = 100;
int nConcats = 1000;

long initialTime = 0L;
long afterStrTime = 0L;
long afterSbfTime = 0L;
long afterSbTime = 0L;

for ( int i = 0; i < nTests; i++ ) {

    initialTime = System.currentTimeMillis();
    str = "";
    sbf = new StringBuffer();
    sb = new StringBuilder();

    for ( int j = 0; j < nConcats; j++ ) {
        str += "foo"; // or str = str + "foo"
    }
    afterStrTime = System.currentTimeMillis();

    for ( int j = 0; j < nConcats; j++ ) {
        sbf.append( "foo" );
    }
    afterSbfTime = System.currentTimeMillis();

    for ( int j = 0; j < nConcats; j++ ) {
        sb.append( "foo" );
    }
    afterSbTime = System.currentTimeMillis();

}

System.out.printf( "%d milliseconds to perform %d concatenations on String\n", afterStrTime - initialTime, nConcats );
System.out.printf( "%d milliseconds to perform %d concatenations on StringBuilder\n", afterSbfTime - afterStrTime, nConcats );
System.out.printf( "%d milliseconds to perform %d concatenations on StringBuffer\n",  afterSbTime - afterSbfTime, nConcats );

StringBuilder は同期されていない (StringBuffer は同期されている) ため、StringBuffer よりも高速であり、どちらも String よりも高速であることがわかります。

于 2012-07-21T16:11:43.257 に答える