Devemos primeiro lembrar as características de três:
1. Definição
Ao olhar para a API, você encontrará essa string, stringbuffer e stringbuilder implementam a interface Charsequence. Embora todos estejam relacionados a cordas, seus mecanismos de processamento são diferentes.
2. Use cenários
Cenários usando a classe String: Em cenários em que as strings não mudam com frequência, as classes de string podem ser usadas, como declarações de constantes e pequeno número de operações variáveis.
Cenários usando a classe StringBuffer: quando as operações de string são frequentemente executadas (como splicing, substituição, exclusão etc.) e em execução em um ambiente multithread, você pode considerar o uso do StringBuffer, como a análise XML, a análise de parâmetros HTTP e o encapsulamento.
Cenários usando a classe StringBuilder: quando as operações de string são frequentemente executadas (como splicing, substituição e exclusão) e executando em um ambiente de thread único, você pode considerar o uso do StringBuilder, como Assembléia de declaração SQL, encapsulamento JSON, etc.
Iii. Análise
Para simplificar, a principal diferença de desempenho entre o tipo de string e o tipo StringBuffer é na verdade que a string é um objeto imutável; portanto, toda vez que você altera o tipo de string, é realmente equivalente a gerar um novo objeto de string e apontar o ponteiro para o novo objeto String. Portanto, é melhor não usar string para strings que mudam de conteúdo com frequência, porque cada geração de objetos terá um impacto no desempenho do sistema, especialmente quando houver muitos objetos referenciados na memória, o GC da JVM começará a funcionar, o que definitivamente será bastante lento.
Se você usar a classe StringBuffer, o resultado será diferente. Cada vez que o resultado operará no próprio objeto StringBuffer, em vez de gerar um novo objeto e alterar a referência do objeto. Portanto, em geral, recomendamos o uso do StringBuffer, especialmente quando os objetos da string são frequentemente alterados. Em alguns casos especiais, o splicing de string de objetos de string é realmente interpretado pela JVM como um splicing de objetos StringBuffer. Portanto, a velocidade dos objetos da string não é mais lenta que os objetos StringBuffer nesses momentos. Especialmente na seguinte geração de objetos de string, a eficiência da string é muito mais rápida que o StringBuffer:
String s1 = "Este é apenas um" + "simples" + "teste"; stringbuffer sb = new StringBuilder ("Este é apenas um"). Append ("simples"). Append ("test");Você ficará surpreso ao descobrir que a velocidade de gerar objetos String S1 é simplesmente muito rápida e, neste momento, o StringBuffer não tem nenhuma vantagem na velocidade. De fato, este é um truque da JVM. Aos olhos da JVM, este
String s1 = "Este é apenas um" + "simples" + "teste";
Na verdade:
String s1 = "Este é apenas um teste simples";
Então é claro que não leva muito tempo. Mas o que você deve observar aqui é que, se sua string vier de outro objeto de string, a velocidade não é tão rápida, por exemplo:
String s2 = "Este é apenas um"; string s3 = "simples"; string s4 = "test"; string s1 = s2 + s3 + s4;
Neste momento, a JVM fará isso de maneira regular da maneira original.
4. Otimização e processamento aprofundados da JVM
Existe realmente o custo de desempenho acima? O splicing de cordas é tão comum, não há otimização especial de processamento? A resposta é que essa otimização é realizada ao compilar .java em bytecode na JVM.
Se um programa Java quiser executar, levará dois períodos, tempo de compilação e tempo de execução. No momento da compilação, o Java JVM (compilador) converte o arquivo java em bytecode. Em tempo de execução, a Java Virtual Machine (JVM) executa o bytecode gerado por tempo de compilação. Durante esses dois períodos, o Java alcançou a chamada compilação e corrida em todos os lugares.
Vamos experimentar o que as otimizações foram feitas durante o período de compilação e criamos um código que pode ter custos de desempenho.
public class concatenation {public static void main (string [] args) {string userName = "Andy"; String Age = "24"; String job = "desenvolvedor"; String info = nome de usuário + idade + trabalho; System.out.println (info); }}Compilar concatenação.java. Obtenha concatenação.class
javac concatenation.java
Em seguida, usamos o Javap para descompilar o arquivo compilado Concatenation.class. Javap -C Concatenation. Se o comando javap não for encontrado, considere adicionar o diretório em que o Javap está localizado na variável de ambiente ou usando o caminho completo do Javap.
17: 22: 04 -Androidyue ~/Workspace_adt/strings/src $ javap -C ConcatenationCompiled de "concatenação.java" concatenação pública {public concatenation (); Código: 0: Aload_0 1: Invokespecial #1 // Método java/lang/objeto. Código: 0: LDC #2 // String Andy 2: store_1 3: ldc #3 // string 24 5: store_2 6: ldc #4 // String Developer 8: store_3 9: novo #5 // classe Java/lang/stringbuilder 12: Dup 13: Invokespecial #6 // Metoding Java/Lang/Lang/Stringbil InvokeVirtual #7 // Método java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 20: Aload_2 21: InvokeVirtual #7 // Método java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 24: Aload_3 25: InvokeVirtual #7 // Método java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 28: InvokeVirtual #8 // Método java/lang/stringbuilder.toString :() ljava/lang/string; 31: Store 4 33: GetStatic #9 // Campo java/lang/System.out: ljava/io/printStream; 36: Aload 4 38: InvokeVirtual #10 // Método java/io/printstream.println: (ljava/lang/string;) v 41: return}Entre eles, o LDC, a loja, etc. estão as instruções Java ByteCode, semelhantes às instruções de montagem. Os seguintes comentários usam conteúdo relacionado a Java para explicação. Podemos ver que existem muitos stringbuilders, mas nós os chamamos no código Java sem exibição. Esta é a otimização feita por Javajvm. Quando o javajvm encontra splicing de string, um objeto Stringbuilder será criado. A emenda por trás dele está realmente chamando o método Apênd do objeto Stringbuilder. Dessa forma, não haverá problemas com os quais estamos preocupados.
5. Confie apenas na otimização da JVM?
Como a JVM nos ajudou a otimizar, é suficiente confiar apenas na otimização da JVM? Claro que não.
Vejamos um pedaço de código que não foi otimizado para baixo desempenho
public void ImplicticUsEstringBuilder (String [] valores) {String result = ""; for (int i = 0; i <valores.Length; i ++) {resultado += valores [i]; } System.out.println (resultado);}Compilar com Javac e ver com Javap
Public void implicousEstringBuilder (java.lang.string []); Código: 0: ldc #11 // string 2: store_2 3: iconst_0 4: istore_3 5: iload_3 6: aload_1 7: ArrayLength 8: if_icmpge 38 11: novo #5 // classe Java/lang/stringbuilder 14: DUP 15: InvokSescial # 18: Aload_2 19: InvokeVirtual #7 // Método java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 22: aload_1 23: iload_3 24: aaload 25: InvokeVirtual #7 // Método java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 28: InvokeVirtual #8 // Método java/lang/stringbuilder.toString :() ljava/lang/string; 31: store_2 32: iinc 3, 1 35: goto 5 38: getstatic #9 // campo java/lang/system.out: ljava/io/printStream; 41: aload_2 42: InvokeVirtual #10 // Método java/io/printStream.println: (ljava/lang/string;) v 45: retornar
Entre eles 8: if_icmpge 38 e 35: goto 5 formam um loop. 8: if_icmpge 38 significa que, se a comparação inteira da pilha de operando da JVM for maior ou igual a (i <o resultado oposto de valores.length), ele saltará para a linha 38 (System.out). 35: Goto 5 significa pular diretamente para a linha 5.
Mas há uma coisa muito importante aqui que a criação de objetos de Stringbuilder ocorre entre loops, o que significa que quantas vezes os loops criarão vários objetos de StringBuilder, o que obviamente não é bom. Código de baixo nível nu.
Otimize -o um pouco para melhorar instantaneamente a qualidade.
public void explicticUsEstringBuilder (String [] valores) {stringbuilder result = new StringBuilder (); for (int i = 0; i <valores.Length; i ++) {resultado.append (valores [i]); }}Informações compiladas correspondentes
11: Aload_1 12: ArrayLength 13: IF_ICMPGE 30 16: Aload_2 17: Aload_1 18: ILOAD_3 19: Aaload 20: InvokeVirtual #7 // Método 23: Pop 24: Iinc 3, 1 27: Goto 10 30: Retorno
Como pode ser visto de cima, 13: if_icmpge 30 e 27: goto 10 formam um loop loop, enquanto 0: o novo #5 está fora do loop, então o StringBuilder não é criado várias vezes.
Em geral, precisamos tentar evitar a criação implícita ou explícita de construtores de cordas no corpo do loop. Portanto, aqueles que entendem como o código é compilado e como ele é executado internamente têm níveis de código relativamente altos.
6. Conclusão
Na maioria dos casos, stringbuffer> string
Java.lang.stringbuffer é uma sequência segura por thread de caracteres variáveis. Um buffer de string semelhante a uma string, mas não pode ser modificado. Embora contenha uma certa sequência de caracteres a qualquer momento, o comprimento e o conteúdo da sequência podem ser alterados por algumas chamadas de método. Os buffers de string podem ser usados com segurança em programas para multithreading. E esses métodos podem ser sincronizados quando necessário; portanto, todas as operações em qualquer instância em particular parecem ocorrer em uma ordem serial consistente com a ordem das chamadas de método feitas por cada encadeamento envolvido.
As principais operações no StringBuffer são os métodos Apêndos e Inserir, que podem ser sobrecarregados para aceitar qualquer tipo de dados. Cada método pode efetivamente converter os dados fornecidos em uma string e, em seguida, anexar ou inserir os caracteres dessa string no buffer da string. O método Apênd sempre adiciona esses caracteres ao final do buffer; O método Insert adiciona caracteres no ponto especificado.
Por exemplo, se Z se referir a um objeto de buffer de string cujo conteúdo atual é "Iniciar", esse método chama Z.Append ("LE") fará com que o buffer de string contenha "Startle" (acumulado); e Z.Insert (4, "LE") alterará o buffer de string para conter "Starlet".
Na maioria dos casos
java.lang.stringbuilder Uma sequência de caracteres variável é nova em Java 5.0. Esta classe fornece uma API compatível com StringBuffer, mas não é garantida que seja sincronizada; portanto, o cenário de uso é um único rosqueado. Esta classe foi projetada para ser um substituto simples para StringBuffer, quando os buffers de string são usados por um único encadeamento (isso é comum). Se possível, é recomendável fazer esta aula primeiro, pois é mais rápido que o StringBuffer na maioria das implementações. Os métodos de uso de ambos são basicamente os mesmos.