Maison  >  Article  >  Java  >  Analyse du code source Java StringBuilder et StringBuffer

Analyse du code source Java StringBuilder et StringBuffer

高洛峰
高洛峰original
2017-01-22 11:28:401190parcourir

StringBuilder et StringBuffer sont deux classes couramment utilisées pour exploiter les chaînes. Comme nous le savons tous, StringBuilder n'est pas sécurisé pour les threads, tandis que StringBuffer est sécurisé pour les threads. Le premier a été ajouté dans JDK1.5 et le second était disponible dans JDK1.0. Analysons leur mise en œuvre interne.

1. Relation d'héritage

public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
 
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence

Comme vous pouvez le constater, la relation d'héritage des deux classes est exactement la même. Serialisable est un indicateur qui peut être sérialisé. L'interface CharSequence comprend les méthodes charAt(), length(), subSequence() et toString(). La classe String implémente également cette interface. L'accent est mis ici sur la classe abstraite AbstractStringBuilder, qui encapsule l'implémentation de la plupart des opérations de StringBuilder et StringBuffer.

2. AbstractStringBuilder

1. Variables et méthodes de construction

char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
  value = new char[capacity];
}

AbstractStringBuilder utilise en interne un tableau char[] pour enregistrer les chaînes, ce qui peut be Spécifier la méthode de capacité initiale lors de la construction.

2. Extension de capacité

public void ensureCapacity(int minimumCapacity) {
  if (minimumCapacity > 0)
    ensureCapacityInternal(minimumCapacity);
}
 private void ensureCapacityInternal(int minimumCapacity) {
  // overflow-conscious code
  if (minimumCapacity - value.length > 0)
    expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
  int newCapacity = value.length * 2 + 2;
  if (newCapacity - minimumCapacity < 0)
    newCapacity = minimumCapacity;
  if (newCapacity < 0) {
    if (minimumCapacity < 0) // overflow
      throw new OutOfMemoryError();
    newCapacity = Integer.MAX_VALUE;
  }
  value = Arrays.copyOf(value, newCapacity);
}

La méthode d'expansion est finalement implémentée par expandCapacity() Dans cette méthode, la capacité est d'abord étendue à la capacité d'origine plus. 2 , si elle est toujours inférieure à la capacité spécifiée à ce moment-là, définissez la nouvelle capacité sur minimumCapacity. Déterminez ensuite si elle déborde. Si tel est le cas, définissez la capacité sur Integer.MAX_VALUE. Enfin, la valeur est copiée, ce qui est évidemment une opération fastidieuse.

3. Méthode append()

public AbstractStringBuilder append(String str) {
    if (str == null)
      return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
  }

append() est la méthode la plus couramment utilisée et elle présente de nombreuses formes de surcharge. Ce qui précède en fait partie, utilisé pour ajouter des chaînes. Si str est nul, la méthode appendNull() sera appelée. Cette méthode ajoute en fait les caractères « n », « u », « l » et « l ». Si elle n'est pas nulle, la capacité est d'abord étendue, puis la méthode getChars() de String est appelée pour ajouter str à la fin de la valeur. Enfin, l'objet lui-même est renvoyé, donc append() peut être appelé en continu.

3. StringBuilder

AbstractStringBuilder a déjà implémenté la plupart des méthodes requises StringBuilder et StringBuffer doivent seulement être appelées. Jetons un coup d'œil à l'implémentation de StringBuilder.

1. Constructeur

public StringBuilder() {
  super(16);
}
public StringBuilder(int capacity) {
  super(capacity);
}
public StringBuilder(String str) {
  super(str.length() + 16);
  append(str);
}
public StringBuilder(CharSequence seq) {
  this(seq.length() + 16);
  append(seq);
}

On peut voir que la capacité par défaut de StringBuilder est de 16. Bien entendu, vous pouvez également spécifier la capacité initiale, ou attribuer une valeur initiale à l'objet StringBuilder avec une séquence de caractères existante.

2. Méthode append()

public StringBuilder append(String str) {
  super.append(str);
  return this;
}
public StringBuilder append(CharSequence s) {
  super.append(s);
  return this;
}

Il existe de nombreuses méthodes surchargées pour append(), en voici seulement deux. Évidemment, voici la méthode de la classe parent AbstractStringBuilder qui est directement appelée.

3. toString()

public String toString() {
  // Create a copy, don&#39;t share the array
  return new String(value, 0, count);
}

La méthode toString() renvoie un nouvel objet String qui ne partage pas de mémoire avec l'objet d'origine. En fait, il en va de même pour la méthode subString() dans AbstractStringBuilder.

4. SringBuffer

StiringBuffer est similaire à StringBuilder, sauf que pour réaliser la synchronisation, de nombreuses méthodes utilisent la modification synchronisée, comme la méthode suivante :

public synchronized int length() {
    return count;
}
public synchronized StringBuffer append(String str) {
  toStringCache = null;
  super.append(str);
  return this;
}
public synchronized void setLength(int newLength) {
  toStringCache = null;
  super.setLength(newLength);
}


Comme vous pouvez le constater, Synchronized est bien ajouté devant la méthode.
De plus, il existe une variable toStringCache dans les méthodes append() et setLength() ci-dessus. Cette variable est utilisée pour le cache de la méthode toString() la plus récente. Chaque fois que le StringBuffer est modifié, cette variable se verra attribuer la valeur null. Le toString de StringBuffer est le suivant :

public synchronized String toString() {
  if (toStringCache == null) {
    toStringCache = Arrays.copyOfRange(value, 0, count);
  }
  return new String(toStringCache, true);
}

Dans cette méthode, si toStringCache est nul, il sera d'abord mis en cache. L'objet String final renvoyé est un peu différent. Ce constructeur a également un paramètre true. Recherchez le code source de String et jetez un œil :

String(char[] value, boolean share) {
  // assert share : "unshared not supported";
  this.value = value;
}

Il s'avère que l'objet String construit par cette méthode de construction ne copie pas réellement la chaîne, mais pointe simplement la valeur au paramètre de construction. Ceci permet d'économiser de l'argent. Le moment où l'élément est copié. Cependant, ce constructeur dispose de droits d'accès aux packages et ne peut pas être appelé dans des circonstances normales.

Résumé

StringBuilder et StringBuffer sont tous deux des chaînes mutables. La première est thread-safe et la seconde est thread-safe.

La plupart des méthodes de StringBuilder et StringBuffer appellent l'implémentation de la classe parent AbstractStringBuilder. Son mécanisme d'expansion modifie d'abord la capacité à 2 fois la capacité d'origine plus 2. La capacité maximale est Integer.MAX_VALUE, soit 0x7ffffffff.

La capacité par défaut de StringBuilder et StringBuffer est de 16. Il est préférable d'estimer la taille de la chaîne à l'avance pour éviter la consommation de temps causée par l'expansion.

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il vous sera utile d'apprendre deux classes couramment utilisées pour exploiter les chaînes en Java, StringBuilder et StringBuffer.

Pour plus d'articles liés à l'analyse du code source Java StringBuilder et StringBuffer, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn