Строка — один из наиболее часто используемых типов данных в Java. Что касается знаний о строках, автор опубликовал несколько статей и многое представил, например:
Серия изучения исходного кода Java 7 (1) — строка
Как создать строку, используя " " или конструктор?
Наконец-то я понял эту мелочь о String
Три картинки, чтобы полностью понять неизменность строк в Java
Почему Java проектирует строки неизменяемыми
Три изображения, чтобы полностью понять принцип и различие подстроки в JDK 6 и JDK 7.
Конкретные детали реализации Switch в Java для целочисленных, символьных и строковых типов
Эта статья также является дополнением к знаниям, связанным со строками в Java, в основном для ознакомления со знаниями, связанными со сращиванием строк. Эта статья основана на jdk1.8.0_181.
Объединение строк {#toc_0}
Конкатенация строк — это то, что мы часто делаем в коде Java, а именно объединение нескольких строк вместе.
мы все знаем,String — это неизменяемый класс в Java., поэтому после создания экземпляра его нельзя изменить.
После создания экземпляра неизменяемого класса значения его переменных-членов не могут быть изменены. Этот дизайн имеет много преимуществ, таких как кеширование хэш-кода, более удобное использование и повышенная безопасность.
Но поскольку строки неизменяемы, как насчет конкатенации строк?
Неизменяемость строк и конкатенация строк
По сути, все так называемое сращивание строк заключается в том, чтобы регенерировать новую строку. Следующий фрагмент кода конкатенации строк:
String s = "abcd";
s = s.concat("ef");
На самом деле конечная s, которую мы получаем, уже является новой строкой. Как показано ниже
В s сохраняется ссылка на воссозданный объект String.
Итак, как в Java выполнить конкатенацию строк? Существует много способов объединения строк, вот некоторые из наиболее часто используемых.
использовать+
объединить строки
В Java самый простой способ конкатенации строк — использовать символы напрямую.+
к сращиванию. как:
String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
String hollis = wechat + "," + introduce;
Вот особый момент, некоторые люди используют Java+
Функция конкатенации строк понимается какперегрузка оператора. Не совсем,Java не поддерживает перегрузку операторов. На самом деле это только один из предоставленных Javaсинтаксический сахар. Подробности позже.
Перегрузка операторов. В компьютерном программировании перегрузка операторов является типом полиморфизма. Перегрузка оператора заключается в переопределении существующего оператора и наделении его другой функцией для адаптации к различным типам данных.
Синтаксический сахар: Синтаксический сахар, также переводимый как «покрытая сахаром грамматика», — это термин, изобретенный британским ученым-компьютерщиком Питером Лендингом для обозначения определенной грамматики, добавленной к компьютерному языку, которая не влияет на функцию языка. удобно для программистов. Синтаксический сахар делает программы более краткими и читабельными.
concat
Помимо использования+
В дополнение к объединению строк вы также можете использовать метод concat в классе String для объединения строк. как:
String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
String hollis = wechat.concat(",").concat(introduce);
StringBuffer
Что касается строк, в дополнение к определению строки, которую можно использовать для определениястроковая константаизString
В дополнение к классам также предусмотрены, которые можно использовать для определениястроковая переменнаяизStringBuffer
Класс, объекты которого можно расширять и изменять.
использоватьStringBuffer
Строки могут быть легко объединены. как:
StringBuffer wechat = new StringBuffer("Hollis");
String introduce = "每日更新Java相关技术文章";
StringBuffer hollis = wechat.append(",").append(introduce);
StringBuilder
КромеStringBuffer
Кроме того, есть классStringBuilder
также может использоваться, его использование иStringBuffer
похожий. как:
StringBuilder wechat = new StringBuilder("Hollis");
String introduce = "每日更新Java相关技术文章";
StringBuilder hollis = wechat.append(",").append(introduce);
StringUtils.join
В дополнение к встроенному методу конкатенации строк в JDK вы также можете использовать имена методов конкатенации строк, предоставленные в некоторых библиотеках классов с открытым исходным кодом, таких какapache.commons中
который предоставилStringUtils
класса, из которыхjoin
метод объединения строк.
String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
System.out.println(StringUtils.join(wechat, ",", introduce));
Вот краткое введение.Основная функция метода соединения, представленного в StringUtils, заключается в объединении массива или коллекции с помощью сплайсера для формирования новой строки, например:
String []list ={"Hollis","每日更新Java相关技术文章"};
String result= StringUtils.join(list,",");
System.out.println(result);
//结果:Hollis,每日更新Java相关技术文章
Кроме того, класс String в Java8 также предоставляет метод статического соединения, который аналогичен по использованию StringUtils.join.
Выше приведены пять наиболее часто используемых способов объединения строк в Java, так какой из них лучше использовать? Почему не рекомендуется использовать его в теле цикла в Руководстве по разработке Java для Alibaba?+
Как насчет конкатенации строк?

(Протокол о сращивании строк в Руководстве по разработке Java для Alibaba)
использовать+
Принцип реализации соединения строк {#toc_1}
Как упоминалось ранее, использование+
Конкатенация строк на самом деле является просто синтаксическим сахаром, предоставляемым Java, поэтому давайте объясним этот синтаксический сахар и посмотрим, как реализуются его внутренние принципы.
Еще этот кусок кода. Давайте декомпилируем сгенерированный им байт-код и посмотрим на результат.
String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
String hollis = wechat + "," + introduce;
Декомпилированное содержимое выглядит следующим образом, а инструмент декомпиляции — jad.
String wechat = "Hollis";
String introduce = "\u6BCF\u65E5\u66F4\u65B0Java\u76F8\u5173\u6280\u672F\u6587\u7AE0";//每日更新Java相关技术文章
String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();
Глядя на код после декомпиляции, мы можем обнаружить, что исходная строковая константа обрабатывается ее методом добавления после преобразования String в StringBuilder в процессе объединения.
То есть в Java+
Сращивание струн осуществляется с помощьюStringBuilder.append
.
Как реализовано объединение {#toc_2}
Давайте взглянем на исходный код метода concat и посмотрим, как этот метод реализован.
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
Этот код сначала создает массив символов, длина которого является суммой длины существующей строки и строки, подлежащей конкатенации, затем копирует значения двух строк в новый массив символов и использует этот массив символов для создания новый объект String и вернуть его.
Из исходного кода мы также можем видеть, что после метода concat фактически создается новая строка, что также перекликается с проблемой инвариантности строки, о которой мы упоминали ранее.
StringBuffer и StringBuilder
Далее посмотримStringBuffer
иStringBuilder
принцип реализации.
иString
класс похожий,StringBuilder
Класс также инкапсулирует массив символов, определенный следующим образом:
char[] value;
иString
Отличие в том, что это неfinal
, поэтому его можно изменить. Кроме того, сString
Различные, не обязательно все позиции в массиве символов были использованы, у него есть переменная экземпляра, которая представляет количество символов, которые были использованы в массиве, определяемом следующим образом:
int count;
Исходный код добавления выглядит следующим образом:
public StringBuilder append(String str) {
super.append(str);
return this;
}
Этот класс наследуетAbstractStringBuilder
класс, посмотри на него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 будет напрямую копировать символы во внутренний массив символов, если длины массива символов недостаточно, он будет расширен.
StringBuffer
иStringBuilder
Аналогично, самая большая разницаStringBuffer
является потокобезопасным, взглянитеStringBuffer
изappend
метод.
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
Этот метод используетsynchronized
Объявите, что это потокобезопасный метод. иStringBuilder
Это не потокобезопасно.
Как реализован StringUtils.join {#toc_4}
просмотревStringUtils.join
В исходном коде мы можем обнаружить, что, собственно, он тоже прошелStringBuilder
быть реализованным.
public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
if (separator == null) {
separator = EMPTY;
}
// endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
// (Assuming that all Strings are roughly equally long)
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = new StringBuilder(noOfItems * 16);
for (int i = startIndex; i < endIndex; i++) {
if (i > startIndex) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
Сравнение эффективности {#toc_5}
Поскольку существует так много способов конкатенации строк, какой из них наиболее эффективен? Проведем простое сравнение.
long t1 = System.currentTimeMillis();
//这里是初始字符串定义
for (int i = 0; i < 50000; i++) {
//这里是字符串拼接代码
}
long t2 = System.currentTimeMillis();
System.out.println("cost:" + (t2 - t1));
Мы используем код приведенной выше формы для проверки времени работы каждого из пяти кодов конкатенации строк. Результат выглядит следующим образом:
+ cost:5119
StringBuilder cost:3
StringBuffer cost:4
concat cost:3623
StringUtils.join cost:25726
Как видно из результатов, сравнение времени от короткого к длинному составляет:
StringBuilder
<StringBuffer
<concat
<+
<StringUtils.join
StringBuffer
существуетStringBuilder
На основе синхронной обработки это займет относительно больше времени.
StringUtils.join тоже использует StringBuilder, и в нем много других операций, так что это занимает много времени, и это легко понять. На самом деле StringUtils.join лучше справляется с конкатенацией строковых массивов или списков.
Затем возникает проблема, которую мы проанализировали ранее, фактически используя+
Также используется принцип реализации сращивания строкStringBuilder
, тогда почему результаты такие разные, до более чем 1000 раз?
Давайте декомпилируем следующий код:
long t1 = System.currentTimeMillis();
String str = "hollis";
for (int i = 0; i < 50000; i++) {
String s = String.valueOf(i);
str += s;
}
long t2 = System.currentTimeMillis();
System.out.println("+ cost:" + (t2 - t1));
Декомпилированный код выглядит следующим образом:
long t1 = System.currentTimeMillis();
String str = "hollis";
for(int i = 0; i < 50000; i++)
{
String s = String.valueOf(i);
str = (new StringBuilder()).append(str).append(s).toString();
}
long t2 = System.currentTimeMillis();
System.out.println((new StringBuilder()).append("+ cost:").append(t2 - t1).toString());
Мы видим, что декомпилированный код вfor
В цикле каждый разnew
взял одинStringBuilder
, а затем положитьString
Превратиться вStringBuilder
, а затем продолжитьappend
.
Конечно, частое создание новых объектов занимает много времени, что не только отнимает время, но и приводит к пустой трате ресурсов памяти.
Поэтому в Руководстве по разработке Java для Alibaba рекомендуются: тело цикла, метод подключения строк, использованиеStringBuilder
изappend
метод расширения. Вместо того, чтобы использовать+
.
Резюме {#toc_6}
В этой статье рассказывается, что такое сращивание строк.Хотя строки неизменяемы, их все же можно сплайсировать путем создания новых строк.
Существует пять широко используемых методов сращивания строк, которые следует использовать.+
,использоватьconcat
,использоватьStringBuilder
,использоватьStringBuffer
и использоватьStringUtils.join
.
Поскольку новые объекты создаются во время конкатенации строк, необходимо учитывать проблемы с памятью и эффективностью, если конкатенация строк должна выполняться в теле цикла.
Поэтому после сравнения мы обнаружили, что непосредственно с помощьюStringBuilder
способ самый действенный. так какStringBuilder
По своей природе он предназначен для определения изменяемых строк и операций изменения строк.
Однако следует также подчеркнуть, что:
1. Если строка не конкатенирована в теле цикла, используйте ее напрямую+
Достаточно.
2. Если конкатенация строк выполняется в параллельных сценариях, используйтеStringBuffer
заменитьStringBuilder
.