11

最初に文字列に値を割り当てるときに、読みやすさを向上させるために文字列を複数の行に分割すると、パフォーマンス コストがかかるのではないかとよく疑問に思います。文字列は不変であるため、毎回新しい文字列を作成する必要があることを知っています。また、今日の非常に高速なハードウェアのおかげで、パフォーマンス コストは実際には無関係です (悪魔のようなループに陥っている場合を除きます)。たとえば、次のようになります。

String newString = "This is a really long long long long long" +
    " long long long long long long long long long long long long " +
    " long long long long long long long long long string for example.";

JVM または .Net のコンパイラおよびその他の最適化は、これをどのように処理しますか。単一の文字列を作成しますか? または、1 つの文字列を作成してから、値を連結した新しい文字列を作成し、次に値を再度連結した別の文字列を作成しますか?

これは私の好奇心のためです。

4

8 に答える 8

28

これは、コンパイル時の定数であるため、単一のリテラルで文字列を作成する場合と同じであることが C# 仕様によって保証されています。C# 3 仕様のセクション 7.18 から:

式が上記の要件を満たす場合は常に、コンパイル時に式が評価されます。これは、式が非定数構造を含むより大きな式の部分式であっても当てはまります。

(「上記の要件」の正確な詳細については、仕様を参照してください:)

Java 言語仕様では、セクション 3.10.5の下部近くでそれを指定しています。

定数式 (§15.28) によって計算された文字列は、コンパイル時に計算され、リテラルであるかのように扱われます。

于 2009-03-02T09:59:04.230 に答える
14

実際、Java では、コンパイラは をString定数に変換します。

class LongLongString
{
    public LongLongString()
    {
        String newString = "This is a really long long long long long" +
            " long long long long long long long long long long long long " +
            " long long long long long long long long long string for example.";
    }

    public static void main(String[] args)
    {
        new LongLongString();
    }
}

次のようにコンパイルされます。

Compiled from "LongLongString.java"
class LongLongString extends java.lang.Object{
public LongLongString();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   ldc #2; //String This is a really long long long long long long long long long long long long long long long long long  long long long long long long long long long string for example.
   6:   astore_1
   7:   return

public static void main(java.lang.String[]);
  Code:
   0:   new #3; //class LongLongString
   3:   dup
   4:   invokespecial   #4; //Method "<init>":()V
   7:   pop
   8:   return

}

Stringご覧のとおり、複数のインスタンスが読み込まれるのではなく、1 行が 4 行目に読み込まれます。

編集:ソース ファイルはjavacバージョン 1.6.0_06 を使用してコンパイルされました。The Java Language Specification, Third Edition (およびJon Skeet's answerで言及されている同じセクション) を見ると、コンパイラが複数行Stringを単一の に連結する必要があるかどうかについての参照を見つけることができなかったStringので、この動作はおそらくコンパイラです実装固有。

于 2009-03-02T10:03:54.313 に答える
5

パフォーマンスのトレードオフはありません。コンパイラの最適化により、それが単一の文字列にマージされます (少なくとも Java では)。

于 2009-03-02T09:59:39.283 に答える
3

coobirdの答えを補完する同等の.NET IL :

C# コードの場合:

string s = "This is a really long long long long long" +
    " long long long long long long long long long long long long " +
    " long long long long long long long long long string for example.";
Console.WriteLine(s);

デバッグ コンパイルでは、次が生成されます。

.method public hidebysig static void Main(string[] args) cil managed
{
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
  .maxstack 1
  .locals init (
      [0] string str)
  L_0000: ldstr "This is a really long long long long long long long long long long long long long long long long long  long long long long long long long long long string for example."
  L_0005: stloc.0 
  L_0006: ldloc.0 
  L_0007: call void [mscorlib]System.Console::WriteLine(string)
  L_000c: ret 
}

ご覧のとおり、1 つの文字列です。

于 2009-03-02T11:04:46.273 に答える
3

私が覚えている限り、これは複数の文字列を作成するのではなく、1 つの文字列だけを作成します。

于 2009-03-02T09:58:12.377 に答える
2

すべての文字列が定数である限り (あなたの例のように)、Java (および私は C# を想像します) では、コンパイラはこれを単一の文字列に変換します。

+ でパフォーマンスの問題が発生するのは、ループなどで多数の動的文字列を連結する場合のみです。この場合、StringBuilder または StringBuffer を使用します。

于 2009-03-02T09:59:51.200 に答える
0

免責事項: これは Java に当てはまります。私はそれがc#に当てはまると思います

javac は単一の文字列を作成するだけでなく、JVM は同じテキストを含む他のすべての文字列に対して 1 つの文字列を使用します。

String a = "He" + "llo th"+ "ere";
String b = "Hell" + "o the"+ "re";
String c = "Hello" +" "+"there";
assert a == b; // these are the same String object.
assert a == c; // these are the same String object.

注: これらは、異なるコンパイラーによってコンパイルされた、異なる JARS の異なるクラスにある場合でも、実行時に同じ String オブジェクトになります。

于 2009-03-02T21:59:46.680 に答える