См. StringBuffer из исходного кода JDK.

Java задняя часть исходный код Безопасность
См. StringBuffer из исходного кода JDK.

Обзор

Строка, которая часто используется при работе со строками в Java, является константой, которую нельзя изменить после создания. Для обеспечения модифицируемых операций введен класс StringBuilder, см. предыдущую статью "См. StringBuilder из исходного кода JDK.". Но он не является потокобезопасным и используется только в однопоточных сценариях. Поэтому для многопоточных сценариев введен потокобезопасный класс StringBuffer.

В общем потокобезопасность достигается добавлением синхронизированных к необходимым методам.

Отношения трех классов строк

这里写图片描述

структура наследования

--java.lang.Object
  --java.lang.AbstractStringBuilder
    --java.lang.StringBuffer

определение класса

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

Класс StringBuffer объявляется окончательным, что означает, что он больше не может быть унаследован. При этом он наследует класс AbstractStringBuilder и реализует интерфейсы Serializable и CharSequence.

Интерфейс Serializable указывает, что его можно сериализовать.

Интерфейс CharSequence используется для получения информации о последовательностях символов.Интерфейс определяется следующим образом:

  • length()Получить длину последовательности символов.
  • charAt(int index)Получить символ, соответствующий индексу.
  • subSequence(int start, int end)Получить указанный диапазон подстрок.
  • toString()Преобразование в строковый объект.
  • chars()Поток значений int, используемый для получения символов последовательности символов, этот интерфейс предоставляет реализацию по умолчанию.
  • codePoints()Поток значений int, используемый для получения кодовых точек последовательности символов, предусмотрена реализация по умолчанию.
public interface CharSequence {

    int length();

    char charAt(int index);

    CharSequence subSequence(int start, int end);

    public String toString();

    public default IntStream chars() {
        省略代码。。
    }

    public default IntStream codePoints() {
        省略代码。。
    }
}

главный атрибут

private transient String toStringCache;
byte[] value;
byte coder;
int count;
  • toStringCache для кеширования вызововtoStringОбъект String, сгенерированный методом, избегает каждый раз генерировать объект String в соответствии с кодировкой.
  • value Этот массив используется для хранения строковых значений.
  • coder представляет кодировщик, используемый этим строковым объектом.
  • count представляет количество символов, используемых в этом строковом объекте.

Метод строительства

Существует несколько методов построения, вы можете указать параметр размера емкости, если он не указан, метод построения создает строковый объект с емкостью 16 по умолчанию. Если COMPACT_STRINGS имеет значение true, то есть используется кодировка LATIN1 (кодировка ISO-8859-1) для компактного макета, откройте массив байтов длиной 16. И если это кодировка UTF16, откройте массив байтов длиной 32.

public StringBuffer() {
        super(16);
    }
    
AbstractStringBuilder(int capacity) {
        if (COMPACT_STRINGS) {
            value = new byte[capacity];
            coder = LATIN1;
        } else {
            value = StringUTF16.newBytesFor(capacity);
            coder = UTF16;
        }
    }
    
public StringBuffer(int capacity) {
        super(capacity);
    }

Если параметр, переданный конструктором, имеет тип String, он откроет длинуstr.length() + 16массив байтов и передатьappendМетод добавляет строковый объект в массив байтов.

public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

Точно так же такая же обработка выполняется, когда входящий параметр имеет тип CharSequence.

public StringBuffer(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }

основной метод

На самом деле, для достижения потокобезопасности самый простой и, возможно, наименее эффективный способ — это синхронизировать определенные методы, чтобы разрешить параллельные операции. Поэтому StringBuffer и StringBuilder имеют почти одинаковую логику реализации и абстрагируются в абстрактный класс AbstractStringBuilder для реализации, но StringBuffer синхронизирует некоторые необходимые методы.

Большинство методов в StringBuffer просто синхронизируются.

Например, приведенный ниже метод добавляет синхронизацию для обеспечения точности подсчета. Кроме того, существует множество других методов, таких какcodePointCount,capacity,ensureCapacity,codePointAt,codePointBefore,charAt,getChars,setCharAt,substring,subSequence,indexOf,lastIndexOf,getBytes.

@Override
public synchronized int length() {
        return count;
    }
    
@Override
public synchronized void setLength(int newLength) {
        toStringCache = null;
        super.setLength(newLength);
    }

метод trimToSize

Этот метод используется для сжатия емкости объекта StringBuffer до длины строки. Этот метод переписан, в основном для добавления синхронизации для обеспечения точности процесса копирования массива.

@Override
public synchronized void trimToSize() {
        super.trimToSize();
    }

public void trimToSize() {
        int length = count << coder;
        if (length < value.length) {
            value = Arrays.copyOf(value, length);
        }
    }

метод добавления

иметь более одногоappendМетоды отличаются только входящими параметрами.Тоже используют синхронизированный.Кроме того он еще и очистит кеш toStringCache.Это потому что значение строки после добавления изменилось,поэтому кеш нужно сбрасывать. К методам сброса кэша также относятся:appendCodePoint,delete,deleteCharAt,replace,insert,reverse.

@Override
public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

метод toString

Используя синхронную операцию, сначала определите, пуст ли кэш, если он пуст, сначала создайте объект String, соответствующий заполнителю кодировки в соответствии с кодировкой (Latin1 или UTF16), а затем создайте новый объект String и верните его.

@Override
public synchronized String toString() {
        if (toStringCache == null) {
            return toStringCache =
                    isLatin1() ? StringLatin1.newString(value, 0, count)
                               : StringUTF16.newString(value, 0, count);
        }
        return new String(toStringCache);
    }

метод writeObject

Этот метод является методом сериализации, который записывает значения полей value, count и shared соответственно.

private synchronized void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        java.io.ObjectOutputStream.PutField fields = s.putFields();
        char[] val = new char[capacity()];
        if (isLatin1()) {
            StringLatin1.getChars(value, 0, count, val, 0);
        } else {
            StringUTF16.getChars(value, 0, count, val, 0);
        }
        fields.put("value", val);
        fields.put("count", count);
        fields.put("shared", false);
        s.writeFields();
    }

метод readObject

Этот метод представляет собой метод десериализации, который считывает значение и количество соответственно и инициализирует массив байтов и идентификатор кодировки в объекте.

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        java.io.ObjectInputStream.GetField fields = s.readFields();
        char[] val = (char[])fields.get("value", null);
        initBytes(val, 0, val.length);
        count = fields.get("count", 0);
    }
    
void initBytes(char[] value, int off, int len) {
        if (String.COMPACT_STRINGS) {
            this.value = StringUTF16.compress(value, off, len);
            if (this.value != null) {
                this.coder = LATIN1;
                return;
            }
        }
        this.coder = UTF16;
        this.value = StringUTF16.toBytes(value, off, len);
    }

------------- Рекомендуем прочитать ------------

Резюме моей статьи за 2017 год — машинное обучение

Краткое изложение моих статей за 2017 год — Java и промежуточное ПО

Резюме моих статей 2017 года — глубокое обучение

Краткое изложение моих статей за 2017 год — исходный код JDK

Резюме моей статьи за 2017 год — обработка естественного языка

Резюме моих статей 2017 года — Java Concurrency


Поговори со мной, задай мне вопросы:

这里写图片描述

Меню официальной учетной записи было разделено на «Сводка для чтения», «Распределенное», «Машинное обучение», «Глубокое обучение», «НЛП», «Глубина Java», «Ядро параллелизма Java», «Исходный код JDK», "Tomcat Core" "Подождите, может быть, есть тот, который соответствует вашему аппетиту.

Зачем писать «Анализ проектирования ядра Tomcat»

Добро пожаловать, чтобы следовать:

这里写图片描述