Acredito que todos entendam bem a diferença entre String e StringBuffer, mas estima-se que ainda existam muitos camaradas que não têm clareza sobre os princípios de funcionamento dessas duas classes. Hoje irei revisar esse conceito para todos, e por. a maneira Há uma nova classe de operação de caracteres introduzida no J2SE 5.0 - StringBuilder. Então, quais são as diferenças entre este StringBuilder e StringBuffer e a classe String que conhecemos? Qual devemos usar em diferentes situações? Gostaria de compartilhar minha opinião sobre essas categorias e espero também que todos possam dar suas opiniões. Todos cometeram erros e, ao corrigi-los, é uma boa oportunidade para aprender.
Resumidamente, a principal diferença de desempenho entre o tipo String e o tipo StringBuffer é, na verdade, que String é um objeto imutável (por quê? Pergunte aos designers de Java, por que String não é um tipo nativo?) Portanto, toda vez que o tipo String é alterado Na verdade, é equivalente a gerar um novo objeto String e, em seguida, apontar o ponteiro para o novo objeto String. Portanto, é melhor não usar String para strings que mudam frequentemente de conteúdo. , porque toda vez que um objeto é gerado, ele terá um impacto no desempenho do sistema. Principalmente quando há muitos objetos não referenciados na memória, o GC da JVM começará a funcionar e a velocidade será definitivamente bastante lenta. Aqui está um exemplo que não é muito apropriado:
Se for esse o caso, após a conclusão do loop for, se os objetos na memória não tiverem sido apagados pelo GC, haverá mais de 20.000 na memória, um número surpreendente, e se este for um sistema usado por muitos gente, então O número não é muito grande, então todos devem ter cuidado ao utilizá-lo.
Se você usar a classe StringBuffer, os resultados serão diferentes. Cada vez que o resultado for uma operação no próprio objeto StringBuffer, em vez de gerar um novo objeto e depois alterar a referência do objeto. Portanto, em geral, recomendamos o uso de StringBuffer, especialmente quando os objetos string mudam com frequência. Em alguns casos especiais, a concatenação de strings de objetos String é na verdade interpretada pela JVM como a concatenação de objetos StringBuffer, portanto, nesses casos, a velocidade dos objetos String não será mais lenta que a dos objetos StringBuffer, e especialmente os seguintes objetos string são gerado Entre eles, a eficiência do String é muito mais rápida que o StringBuffer:
Você ficará surpreso ao descobrir que a velocidade de geração de objetos String S1 é simplesmente muito rápida e, neste momento, StringBuffer não tem nenhuma vantagem em velocidade. Na verdade, este é um truque da JVM. Aos olhos da JVM, isso.
Disto chegamos à conclusão do primeiro passo: Na maioria dos casos StringBuffer > String
E como o StringBuilder se compara a eles? Deixe-me apresentá-lo brevemente primeiro. StringBuilder é uma classe recém-adicionada no JDK5.0. A diferença entre ele e StringBuffer é a seguinte (fonte: JavaWorld):
Java.lang.StringBuffer Sequência de caracteres mutáveis thread-safe. Um buffer de string semelhante a String, mas não pode ser modificado. Buffers de string podem ser usados com segurança por vários threads. Esses métodos podem ser sincronizados quando necessário, de modo que todas as operações em qualquer instância específica pareçam ocorrer em uma ordem serial consistente com a ordem das chamadas de método feitas por cada thread envolvido.
Cada buffer de string tem uma certa capacidade. Contanto que o comprimento da sequência de caracteres contida no buffer de string não exceda essa capacidade, não há necessidade de alocar uma nova matriz de buffer interna. Esta capacidade é aumentada automaticamente se o buffer interno transbordar. A partir do JDK 5.0, uma classe equivalente para uso de thread único, StringBuilder, foi adicionada a esta classe. A classe StringBuilder geralmente deve ser usada em preferência a esta classe porque suporta todas as mesmas operações, mas é mais rápida porque não executa sincronização.
Mas não é seguro usar uma instância do StringBuilder com vários threads. Se tal sincronização for necessária, é recomendado usar StringBuffer.
Dito isso, acho que todos podem entender a diferença entre eles, então vamos fazer uma derivação geral abaixo:
Na maioria dos casos StringBuilder > StringBuffer
Portanto, de acordo com o teorema transitivo desta desigualdade: Na maioria dos casos StringBuilder > StringBuffer > String
Agora que temos esses resultados de derivação, vamos fazer um teste para verificar:
O código de teste é o seguinte:
/** Cria uma nova instância de testessb */
final static int ttime = 10000;//Número de loops de teste
testes públicossb() {
}
teste de void público(String s){
início longo = System.currentTimeMillis();
for(int i=0;i<time;i++){
s += "adicionar";
}
muito tempo = System.currentTimeMillis();
System.out.println("O tempo utilizado pela operação do tipo "+s.getClass().getName()+" é: " + (over - start) + " milissegundos" );
}
teste de void público(StringBuffers){
início longo = System.currentTimeMillis();
for(int i=0;i<time;i++){
s.append("adicionar");
}
muito tempo = System.currentTimeMillis();
System.out.println("O tempo utilizado pela operação do tipo "+s.getClass().getName()+" é: " + (over - start) + " milissegundos" );
}
teste de void público(StringBuilders){
início longo = System.currentTimeMillis();
for(int i=0;i<time;i++){
s.append("adicionar");
}
muito tempo = System.currentTimeMillis();
System.out.println("O tempo utilizado pela operação do tipo "+s.getClass().getName()+" é: " + (over - start) + " milissegundos" );
}
// Testa diretamente a concatenação de strings em String
público void teste2(){
String s2 = "abadf";
início longo = System.currentTimeMillis();
for(int i=0;i<time;i++){
Sequência s = s2 + s2 + s2 ;
}
muito tempo = System.currentTimeMillis();
System.out.println("O tempo usado para operar o tipo de adição de referência de objeto string é: " + (over - start) + " milissegundos" );
}
público void teste3(){
início longo = System.currentTimeMillis();
for(int i=0;i<time;i++){
String s = "abadf" + "abadf" + "abadf" ;
}
muito tempo = System.currentTimeMillis();
System.out.println("O tempo usado para adicionar strings de operação é: "+ (over - start) + " milissegundos");
}
public static void main(String[] args){
String s1="abc";
StringBuffer sb1 = new StringBuffer("abc");
StringBuilder sb2 = new StringBuilder("abc");
testessb t = novos testessb();
t.teste(s1);
t.teste(sb1);
t.teste(sb2);
t.teste2();
t.teste3();
}
}
Parece que você ainda não consegue ver a diferença entre StringBuffer e StringBuilder Adicione ttime a 30.000 vezes e veja:
O tempo usado para operar o tipo java.lang.String é: 53444 milissegundos O tempo usado para operar o tipo java.lang.StringBuffer é: 15 milissegundos O tempo usado para operar o tipo java.lang.StringBuilder é: 15 milissegundos O tempo usado para operar o tipo de adição de referência de objeto string Tempo gasto: 31 milissegundos A adição de strings demorou: 0 milissegundos
Ainda não há muita diferença de desempenho entre StringBuffer e StringBuilder. Vamos aumentá-lo para 100.000 e dar uma olhada. Não adicionaremos o teste para o tipo String aqui, porque será necessário testar uma quantidade tão grande de dados para o tipo String. muito lento...
O tempo necessário para operar o tipo java.lang.StringBuffer é: 31 milissegundos O tempo necessário para operar o tipo java.lang.StringBuilder é: 16 milissegundos
Você pode ver a diferença, mas muitos dos resultados dos testes mostram que StringBuffer é mais rápido que StringBuilder. Vamos aumentar o valor para 1000000 e ver (não deve travar, certo?):
O tempo necessário para operar o tipo java.lang.StringBuffer é: 265 milissegundos O tempo necessário para operar o tipo java.lang.StringBuilder é: 219 milissegundos
Existem menos diferenças e os resultados são muito estáveis. Vejamos um pouco mais, ttime = 5.000.000:
・・・・・・ Exceção no thread "main" java.lang.OutOfMemoryError: espaço de heap Java ・・・・・・
Haha, esqueça, não vou testar mais. Basicamente, o desempenho é StringBuilder > StringBuffer > String.