Vamos considerar uma pergunta sobre string em java: a diferença entre "ABC" + '/' e "ABC" + "/". Através deste exemplo, podemos praticar o uso do Javap nas ferramentas JDK. A pergunta original é a seguinte:
Qual é a diferença entre tratar barras/como caracteres ou cordas?
Um é usado como o tipo básico de dados, e o outro é a sequência de objetos. Qual é a diferença específica?
Será mais eficiente tratá -lo como um personagem?
String str = "abc" + '/';
e
String str = "abc" + "/";
1. Otimização do compilador
Primeiro de tudo, você deve saber que as duas frases acima têm o mesmo efeito, porque o compilador otimizará as duas frases acima para o seguinte:
String str = "abc/";
Podemos provar isso através do Javap. Para o Javap, podemos nos referir a "5 ferramentas JDK que todo desenvolvedor Java deve conhecer". Primeiro, criamos uma classe: stringone e preencher o código a seguir no método principal:
StringOne.javstring str1 = "abc" + '/'; string str2 = "abc" + "/" ;system.out.println(str1 == str2);
Compilar e executar, o resultado da saída é verdadeiro. Em seguida, nosso Javap é lançado, digite o seguinte comando na linha de comando:
javap -v -l stringone.class> stringone.s
Em seguida, verifique o arquivo StringOne.s gerado. Você descobrirá que existem várias linhas nele
Stringone.s #2 = string #20 // abc /...# 20 = utf8 abc/... 0: ldc #2 // string abc/2: store_13: ldc #2 // string abc/5: store_2
Explicação: STR1 e STR2 se referem à string "ABC/".
2. Use Javap para analisar as diferenças
Agora vamos mudar a pergunta. Qual é a diferença entre os métodos StringAddString e StringAddchar no código a seguir?
Stringtwopublic estático string stringaddString (string str1, string str2) {return str1 + str2;} public static string stringaddchar (string str, char ch) {return str + ch;}Desta vez, o Javap é usado para descompilação, e alguns dos conteúdos do arquivo gerado são os seguintes
Stringtwo.spublic java.lang.string stringaddstring (java.lang.string, java.lang.string); Descritor: (ljava/lang/string; ljava/lang/string;) ljava/lang/string; sinalizadores: acc_public Código: Stack = 2, habitantes locais = 3, args_size = 3 0: novo #2 // classe java/lang/stringbuilder 3: dup 4: InvokesPial #3 // método java/Lang/Stringbuilder. Anexar: (ljava/lang/string;) ljava/lang/stringbuilder; 11: Aload_2 12: InvokeVirtual #4 // Método Java/Lang/StringBuilder. Anexar: (ljava/lang/string;) ljava/lang/stringbuilder; 15: InvokeVirtual #5 // Método Java/Lang/StringBuilder. toString :() ljava/lang/string; 18: Areturnpublic java.lang.string stringaddchar (java.lang.string, char); descritor: (ljava/lang/string; c) ljava/lang/string; Sinalizadores: Acc_public Código: Stack = 2, habitantes locais = 3, args_size = 3 0: novo #2 // classe java/lang/stringbuilder 3: dup 4: Invokespial #3 // Método Java/Lang/Stringbuilder. java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 11: ILOAD_2 12: InvokeVirtual #6 // Método java/lang/stringbuilder.append: (c) ljava/lang/stringbuilder; 15: InvokeVirtual #5 // Método java/lang/stringbuilder.toString :() ljava/lang/string; 18: Areturn
Agora, podemos ver claramente o processo de execução desses dois métodos:
stringaddstring
O procedimento de StringAddchar é o mesmo que o StringAddString, exceto que, quando o método do APÊNHO é chamado na segunda vez, o parâmetro do StringAddString é do tipo String, enquanto o parâmetro de StringAddchar é do tipo de char.
3. Método Anexar (Char) e Anexar (String) Método da classe StringBuilder
Aqui, só precisamos verificar diretamente o código -fonte (o meu é o código -fonte que vem com o JDK1.8.0_60). Observe que, embora o documento mostre que o StringBuilder herda do objeto, a partir do código -fonte, ele é herdado da classe abstrata AbstractStringBuilder. E o método Apênd é implementado pelo AbstractStringBuilder.
AbstractStringBuilder.java
public abstractStringBuilder Append (char c) {securEcapacityInternal (contagem + 1); // Verifique se a matriz pode acomodar a contagem+1 valor de caracteres [count ++] = c; Retornar isso;} public abstringStringBuilder Append (String str) {if (str == null) retornar appendNull (); int len = str.Length (); garantir o internal (contagem + len); str.getchars (0, len, valor, contagem); // Copie a matriz de caracteres na string na matriz de caracteres desta contagem de objetos += len; devolver isso;}O resto não será mais postado. String.getchars (int, int, char [], int) depende de Arraycopy de vazio nativo estático público (objeto, int, objeto, int, int). Em outras palavras, pode ser escrito no idioma C, e a eficiência deve ser melhor ao copiar grandes matrizes do que os programas escritos em Java. Então, agora deixe -me dizer o que eu entendo:
Em termos de memória direta, como a string contém matrizes de char, a matriz deve ter campos de comprimento. Ao mesmo tempo, a classe String também possui uma propriedade int hash, e o próprio objeto ocupará memória adicional para armazenar outras informações; portanto, a string ocupará mais memória. No entanto, se a string for muito longa, essas despesas gerais de memória poderão ser quase ignoradas; E se a string for (muito) curta, existem muitas referências compartilhadas para compartilhar essas despesas gerais de memória, para que o excesso de sobrecarga da memória ainda possa ser ignorado.
A partir da pilha de chamadas, uma vez que a string possui apenas mais uma ou duas chamadas de função que o char aqui, se a sobrecarga de chamada de função (incluindo tempo e espaço) não for considerada, deve ser semelhante; Se a sobrecarga da chamada de função for considerada "ABC" + '/' deve ser melhor; Mas quando vários caracteres precisam ser conectados (acho que essa situação deve ser mais comum, certo?), Uma vez que o uso de char exige muitos loops para concluir a conexão, o número de funções chamadas só será mais chamado do que o uso da string. Ao mesmo tempo, a cópia não será mais rápida do que a string cópia diretamente de uma matriz. Então, neste momento, ele se torna "ABC" + "/" com uma taxa de transferência maior.
Agora sinto que esta pergunta está perguntando: é mais eficiente usar chamadas do sistema ao ler e escrever arquivos ou é mais eficiente usar a biblioteca de IO na biblioteca de funções padrão. Pessoalmente, sinto que, embora a biblioteca de IO padrão precise chamar chamadas do sistema no final, e algumas variáveis temporárias e pilhas de chamadas mais profundas serão geradas, devido aos mecanismos de buffer da biblioteca de IO, a taxa de transferência da biblioteca de IO será maior e o desempenho em tempo real das chamadas do sistema será melhor. Da mesma forma, embora a classe String tenha mais campos e uma pilha de funções mais profunda, a taxa de transferência deve ser melhor devido ao cache e à cópia mais direta.
Novas perguntas
A julgar pelo código de decomposição Javap acima, quando as duas seqüências forem adicionadas, elas se tornarão strings no StringBuilder. Então, em teoria, qual dos seguintes código é mais eficiente?
String str1 = "abc" + "123"; // 1StringBuilder StringBuilder = new StringBuilder (); // 2StringBuilder.Append ("ABC"); Stringbuilder.append ("123"); String str2 = stringbuilder.toString ();Que essa pergunta seja deixada para que todos pensem!
O acima exposto é todo o conteúdo deste artigo, que ajuda a distinguir melhor a string+string e a string+char em java. Espero que seja útil para o aprendizado de todos.