Je pense que tout le monde comprend bien la différence entre String et StringBuffer, mais on estime qu'il y a encore de nombreux camarades qui ne comprennent pas clairement les principes de fonctionnement de ces deux classes. Aujourd'hui, je vais passer en revue ce concept pour tout le monde, et par. la façon dont Il existe une nouvelle classe d'opérations sur les caractères introduite dans J2SE 5.0 - StringBuilder. Alors, quelles sont les différences entre ce StringBuilder et StringBuffer et la classe String que nous avons rencontrée pour la première fois ? Lequel devrions-nous utiliser dans différentes situations ? J'aimerais partager mon point de vue sur ces catégories, et j'espère aussi que chacun pourra donner son avis. Tout le monde a fait des erreurs, et en les corrigeant, c'est une bonne opportunité d'apprendre.
En bref, la principale différence de performances entre le type String et le type StringBuffer est en fait que String est un objet immuable (Pourquoi ? Demandez aux concepteurs de Java, pourquoi String n'est-il pas un type natif ?) Par conséquent, chaque fois que le type String est modifié , En fait, cela équivaut à générer un nouvel objet String, puis à pointer le pointeur vers le nouvel objet String. Par conséquent, il est préférable de ne pas utiliser String pour les chaînes qui changent souvent de contenu. , car chaque fois qu'un objet est généré, cela aura un impact sur les performances du système. Surtout lorsqu'il y a trop d'objets non référencés dans la mémoire, le GC de la JVM commencera à fonctionner et la vitesse sera certainement assez lente. Voici un exemple qui n'est pas très approprié :
Si tel est le cas, une fois la boucle for terminée, si les objets en mémoire n'ont pas été effacés par le GC, il y en aura plus de 20 000 en mémoire, un nombre étonnant, et s'il s'agit d'un système utilisé par de nombreuses personnes les gens, alors Le nombre n'est pas très grand, donc tout le monde doit être prudent lorsqu'il l'utilise.
Si vous utilisez la classe StringBuffer, les résultats seront différents à chaque fois, le résultat sera une opération sur l'objet StringBuffer lui-même, au lieu de générer un nouvel objet puis de modifier la référence de l'objet. Donc, en général, nous recommandons d'utiliser StringBuffer, en particulier lorsque les objets chaîne changent fréquemment. Dans certains cas particuliers, la concaténation de chaînes d'objets String est en fait interprétée par la JVM comme la concaténation d'objets StringBuffer, donc dans ces cas, la vitesse des objets String ne sera pas plus lente que celle des objets StringBuffer, et en particulier les objets chaîne suivants sont généré Parmi eux, l'efficacité de String est beaucoup plus rapide que StringBuffer :
Vous serez surpris de constater que la vitesse de génération des objets String S1 est tout simplement trop rapide et qu'à l'heure actuelle, StringBuffer n'a aucun avantage en termes de vitesse. En fait, c'est une astuce de la JVM. Aux yeux de la JVM, c'est cela.
De là, nous obtenons la première conclusion : dans la plupart des cas, StringBuffer > String
Et comment StringBuilder se compare-t-il à eux ? Permettez-moi d'abord de le présenter brièvement. StringBuilder est une classe nouvellement ajoutée dans JDK5.0. La différence entre elle et StringBuffer est la suivante (source : JavaWorld) :
Java.lang.StringBuffer Séquence de caractères mutables thread-safe. Un tampon de chaîne similaire à String, mais ne peut pas être modifié. Les tampons de chaînes peuvent être utilisés en toute sécurité par plusieurs threads. Ces méthodes peuvent être synchronisées si nécessaire, de sorte que toutes les opérations sur une instance particulière semblent se produire dans un ordre sériel cohérent avec l'ordre des appels de méthode effectués par chaque thread impliqué.
Chaque tampon de chaîne a une certaine capacité. Tant que la longueur de la séquence de caractères contenue par le tampon de chaîne ne dépasse pas cette capacité, il n'est pas nécessaire d'allouer un nouveau tableau de tampon interne. Cette capacité est automatiquement augmentée en cas de débordement du buffer interne. À partir du JDK 5.0, une classe équivalente pour une utilisation avec un seul thread, StringBuilder, a été ajoutée à cette classe. La classe StringBuilder doit généralement être utilisée de préférence à cette classe car elle prend en charge toutes les mêmes opérations mais est plus rapide car elle n'effectue pas de synchronisation.
Mais il n'est pas sûr d'utiliser une instance de StringBuilder avec plusieurs threads. Si une telle synchronisation est requise, il est recommandé d'utiliser StringBuffer.
Cela dit, je pense que tout le monde peut comprendre la différence entre eux, faisons donc une dérivation générale ci-dessous :
Dans la plupart des cas StringBuilder > StringBuffer
Donc, selon le théorème transitif de cette inégalité : Dans la plupart des cas StringBuilder > StringBuffer > String
Maintenant que nous disposons de ces résultats de dérivation, faisons un test pour vérifier :
Le code du test est le suivant :
/** Crée une nouvelle instance de testssb */
final static int ttime = 10000 ;//Nombre de boucles de test
tests publicssb() {
}
test de vide public (String s) {
long start = System.currentTimeMillis();
pour(int i=0;i<ttime;i++){
s += "ajouter" ;
}
depuis longtemps = System.currentTimeMillis();
System.out.println("Le temps utilisé par l'opération de type "+s.getClass().getName()+" est : " + (over - start) + " millisecondes" );
}
test de vide public (StringBuffer s) {
long start = System.currentTimeMillis();
pour(int i=0;i<ttime;i++){
s.append("ajouter");
}
depuis longtemps = System.currentTimeMillis();
System.out.println("Le temps utilisé par l'opération de type "+s.getClass().getName()+" est : " + (over - start) + " millisecondes" );
}
test de vide public (StringBuilder s) {
long start = System.currentTimeMillis();
pour(int i=0;i<ttime;i++){
s.append("ajouter");
}
depuis longtemps = System.currentTimeMillis();
System.out.println("Le temps utilisé par l'opération de type "+s.getClass().getName()+" est : " + (over - start) + " millisecondes" );
}
// Teste directement la concaténation de chaînes sur String
test vide public2(){
Chaîne s2 = "abadf" ;
long start = System.currentTimeMillis();
pour(int i=0;i<ttime;i++){
Chaîne s = s2 + s2 + s2 ;
}
depuis longtemps = System.currentTimeMillis();
System.out.println("Le temps utilisé pour faire fonctionner le type d'ajout de référence d'objet chaîne est : " + (over - start) + " millisecondes" );
}
public void test3(){
long start = System.currentTimeMillis();
pour(int i=0;i<ttime;i++){
Chaîne s = "abadf" + "abadf" + "abadf" ;
}
depuis longtemps = System.currentTimeMillis();
System.out.println("Le temps utilisé pour ajouter des chaînes d'opération est : "+ (over - start) + " millisecondes" );
}
public static void main (String[] args){
Chaîne s1="abc" ;
StringBuffer sb1 = new StringBuffer("abc");
StringBuilder sb2 = new StringBuilder("abc");
testssb t = new testssb();
t.test(s1);
t.test(sb1);
t.test(sb2);
t.test2();
t.test3();
}
}
Il semble que vous ne voyez toujours pas la différence entre StringBuffer et StringBuilder. Ajoutez ttime à 30 000 fois et voyez :
Le temps utilisé pour faire fonctionner le type java.lang.String est : 53444 millisecondes Le temps utilisé pour faire fonctionner le type java.lang.StringBuffer est : 15 millisecondes Le temps utilisé pour faire fonctionner le type java.lang.StringBuilder est : 15 millisecondes Le temps utilisé pour faire fonctionner le type d'ajout de référence d'objet chaîne Temps pris : 31 millisecondes L'ajout de chaînes a pris le temps : 0 millisecondes
Il n'y a toujours pas beaucoup de différence de performances entre StringBuffer et StringBuilder. Augmentons-le à 100 000 et jetons un coup d'œil. Nous n'ajouterons pas le test pour le type String ici, car tester une si grande quantité de données pour le type String sera nécessaire. très lent...
Le temps nécessaire pour faire fonctionner le type java.lang.StringBuffer est : 31 millisecondes Le temps nécessaire pour faire fonctionner le type java.lang.StringBuilder est : 16 millisecondes
Vous pouvez voir la différence, mais de nombreux résultats de tests montrent que StringBuffer est plus rapide que StringBuilder. Augmentons la valeur à 1 000 000 et voyons (il ne devrait pas planter, n'est-ce pas ?) :
Le temps nécessaire pour faire fonctionner le type java.lang.StringBuffer est : 265 millisecondes Le temps nécessaire pour faire fonctionner le type java.lang.StringBuilder est : 219 millisecondes
Il y a moins de différences, et les résultats sont très stables. Regardons cela un peu plus grand, ttime = 5 000 000 :
・・・・・・ Exception dans le thread "main" java.lang.OutOfMemoryError : espace de tas Java ・・・・・・
Haha, oublie ça, je ne le testerai plus. En gros, la performance est StringBuilder > StringBuffer > String.