Pergunta

Muitas vezes me perguntei isso, há um custo de desempenho de dividir uma string em várias linhas para aumentar a legibilidade quando inicialmente atribuir um valor a uma string. Eu sei que strings são imutáveis ??e, portanto, uma nova string precisa ser criado de cada vez. Além disso, o custo de desempenho é realmente irrelevantes graças ao hardware muito rápido de hoje (a menos que você está em algum laço diabólico). Assim, por exemplo:

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.";

Como é que o compilador JVM ou .Net da e outras otimizações lidar com isso. Será que vai criar uma única corda? Ou ele irá criar uma corda, em seguida, um concatenando o novo valor e, em seguida, um outro concatenando os valores novamente?

Isto é para minha própria curiosidade.

Foi útil?

Solução

Este é garantida pela C # especificação para ser idêntico ao criar a string em um único literal, porque é uma constante de tempo de compilação. De seção 7,18 do C # 3 spec:

Sempre que uma expressão cumpre a requisitos listados acima, o expressão é avaliada na em tempo de compilação. Isto é verdadeiro mesmo se o expressão é uma sub-expressão de um expressão maior que contenha construções não-constantes.

(Veja as especificações para os detalhes exatos de "os requisitos listados acima":)

O Java Specification Language especifica-lo perto da parte inferior seção 3.10.5 :

Cordas calculado pela constante expressões (§15.28) são calculados em o tempo de compilação e depois tratou-se como se eles eram literais.

Outras dicas

De fato, em Java, o compilador irá transformar o String em uma constante.

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();
    }
}

é compilado em:

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

}

Como pode ser visto, uma única linha é carregado no em linha 4, em vez de múltiplas instâncias String a ser carregado no.

Editar: O arquivo de origem foi compilado usando javac versão 1.6.0_06. Olhando para The Java Language Specification, terceira edição , (e a mesma secção mencionado em resposta de Jon Skeet), eu não era capaz de encontrar qualquer referência para saber se um compilador deve concatenar uma String multi-linha em um único String, de modo que este comportamento é específico de implementação, provavelmente compilador.

Test isso por si mesmo. No código C # (equivalente Java iria trabalhar muito):

string x = "A" + "B" + "C";
string y = "ABC";

bool same = object.ReferenceEquals(x, y); // true

Você vai ver que o resultado é true.

Como um aparte, você vai ver que a cadeia também está internado em conjunto de cadeia do tempo de execução:

bool interned = object.ReferenceEquals(x, string.Intern(x)); // true

No desempenho troca. otimização do compilador irá mesclar isso com uma única corda (pelo menos em Java).

Tanto quanto me lembro, isso não vai criar várias cordas, apenas uma.

O equivalente .NET IL para complementar o coobird resposta :

Para código 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);

Uma compilação de depuração produz:

.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 
}

Então, como você pode ver, é uma string.

Enquanto todas as cordas são constantes (como eles estão no seu exemplo), em Java (e imagino C #) os convertidos compilador isto a uma única cadeia.

Você só tem problemas de desempenho com + se você concatenar um monte de cordas dinâmicas, como em um loop. Neste caso, use um StringBuilder ou StringBuffer.

Disclaimer: Isto é verdade para Java. Gostaria de assumir o seu verdadeiro para c #

Não só javac criar uma única corda, mas a JVM vai usar uma corda para todas as outras cordas que contêm o mesmo texto.

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.

Nota:. Eles vão ser o mesmo objeto String em tempo de execução, mesmo se eles estão em diferentes classes em diferentes JARS, compilados por diferentes compiladores

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top