Directorio
Variables miembro y métodos de construcción.
Variables miembro y métodos de construcción.
Variables miembro y métodos de construcción.
Introduccion
Bajo JDK1.8, String, StringBuilder y StringBuffer se usan comúnmente para manipular cadenas. String es una secuencia inmutable de caracteres, y StringBuilder y StringBuffer son secuencias variables de caracteres. StringBuilder no es seguro para subprocesos, String y StringBuilder son seguros para subprocesos. Analicemos su implementación interna.
Cuerda
Herencia
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
Como puede ver, String implementa las interfaces Serializable , Comparable y CharSequence . Serializable es una marca serializable. La interfaz comparable contiene el método compareTo () . La interfaz CharSequence contiene los métodos charAt () , length () , subSequence () y toString () .
Variables miembro y métodos de construcción.
private final char value[];
private int hash; // Default to 0
public String() {
this.value = "".value;
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
La cadena utiliza una matriz char [] constante para almacenar la cadena, que es inmutable. La matriz Char [] se convierte al tipo String , que es una copia profunda a través del método Arrays copyOff (), copiando la matriz char [] local y asignándola a la matriz char [] constante .
StringBuilder 和 StringBuffer
Herencia
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
Se puede ver que las clases e interfaces implementadas por StringBuilder y StringBuffer son exactamente las mismas, y las interfaces Serializable y CharSquence se implementan como String . Lo más importante es que la clase abstracta heredada AbstractStringBuilder encapsula la mayoría de los métodos de StringBuilder y StringBuffer.
AbstractStringBuilder
Variables miembro y métodos de construcción.
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
AbstractStringBuilder también define una matriz char [] para almacenar la cadena, pero no se modifica con final , por lo que la cadena es variable. Al mismo tiempo, también se define una variable global cout de tipo int . Cuando la configuración puede especificar la capacidad inicial de la capacidad , con el fin de obtener un mejor rendimiento.
Método de expansión
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
El método de expansión de AbstractStringBuilder es implementado por newCapacity () . En este método, la capacidad se expande al doble de la capacidad original (se usa la operación de cambio en lugar de *) y se agrega 2. Si la capacidad expandida es menor que la capacidad especificada, establezca minCapacity en la última capacidad. Si el valor máximo de Integer ( 0x7fffffff ) menos 8 es menor que la última capacidad, llame al método hugeCapacity () . Para determinar si se desborda, arroje una excepción OutOfMemoryError si se desborda; de lo contrario, si la nueva capacidad es mayor que el valor máximo de Integer menos 8, establezca la capacidad en minCapacity , de lo contrario, ajústelo al valor máximo de Integer menos 8. Si el valor máximo de Integer ( 0x7fffffff ) menos 8 es mayor que la última capacidad, de lo contrario, la capacidad se establece en newCapacity .
método append ()
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
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;
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
El método append () es el método más utilizado de StringBuilder y StringBuffer, sobrecargando muchos métodos para agregar cadenas. El primer método append () convierte el objeto obj al tipo String y lo agrega a través del método valueOf () del String . El segundo append () método, si str es nula , entonces la llamada () appendNull método, primero de expansión ( capacidad bruta plus 4 ), entonces un adicional 'n-' , 'U' , 'L' , 'L' de los cuatro Carácter Si str no es nulo , primera expansión ( capacidad bruta más la longitud de la cadena ), entonces llamar Cadena de getChars () método, str añade a la char [] array valor al final, y, finalmente, la capacidad deCapacidad original + longitud de cadena , devuelve el objeto en sí, para que pueda llamar continuamente al método append () .
StringBuilder
Método de construcción
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
Se puede ver que la capacidad predeterminada de StringBuilder es 16 , y su capacidad inicial también se puede especificar. Si asigna un objeto StringBuilder con una cadena, la capacidad de StringBuiler en este momento es la longitud de la cadena actual más 16 .
método append ()
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
El método append () en StringBuilder es un método para reescribir la clase abstracta AbstractStringBuilder , sobrecargando muchos métodos append () . La implementación de sus métodos es llamar al método append () de la clase padre AbstractStringBuilder . Cuando varios subprocesos acceden a este método, porque el recuento es una variable global, cuando varios subprocesos ejecutan el recuento + = len , habrá problemas con el valor del recuento, lo que provocará una inconsistencia con el real, por lo que el subproceso StringBuilder no es seguro .
Método toString ()
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
StringBuilder reescribir el objeto 's toString () métodos, nueva nueva Stirng () llama internamente las matrices de copyOfRange () método ( copia en profundidad ), devuelve un nuevo objeto String, no un espacio de memoria compartida con el objeto original.
StringBuffer
Variables miembro y métodos de construcción.
private transient char[] toStringCache;
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
Cuando se construye, el StringBuffer y StringBuilder como predeterminado tamaño de la capacidad de 16 , puede especificar la capacidad inicial. La única diferencia es que StringBuffer define una matriz char [] para StringCache decorada con transitorios . palabra clave transitoria , al modificar una variable, la variable no se puede serializar.
método append ()
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
Se puede ver que StringBuffer y StringBuilder reescriben el método append () de la clase padre de AbstractStringBuilder , implementan internamente el método append () de la clase padre y sobrecargan muchos métodos append () . La única diferencia es que cada vez que StringBuffer modifica los datos, la matriz char [] toStringCache se configurará como vacía, y cada método de StringBuffer está precedido por la palabra clave sincronizada . Cuando varios subprocesos acceden a este método, un subproceso está accediendo a este método, y otros subprocesos se bloquearán y no podrán acceder a este método. Solo cuando este subproceso ejecuta este método y libera el bloqueo, otros subprocesos pueden acceder a este método, por lo que StringBuffer Es seguro para el hilo .
Método toString ()
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
StringBuffer 's toString () método y StringBuilder no es lo mismo. Si toStringCache es nulo , primero se almacena en caché y finalmente devuelve un objeto String . StringBuffer la nueva cadena () una interna no llame Arrays de copyOfRange () método, simplemente asignación array ( copia superficial ), copia los elementos para ahorrar tiempo.
Resumen
- String es una cadena inmutable , StringBuffer y StringBuilder son cadenas variables .
- StringBuilder no es seguro para subprocesos y es rápido , y StringBuffer es seguro para subprocesos y lento .
- La mayoría de los métodos de StringBuilder y StringBuffer llaman a la implementación de la clase padre AbstractStringBuilder. El mecanismo de expansión es aumentar primero la capacidad a 2 veces la capacidad original más 2 . La capacidad máxima es el valor máximo de Integer (0x7fffffff) menos 8 .
- La capacidad predeterminada de StringBuilder y StringBuffer son 16 , puede especificar el tamaño al crear StringBuffer y StringBuilder, para evitar el crecimiento automático cuando la capacidad no es suficiente para mejorar el rendimiento.