Какова стоимость исполнения для назначения одного строкового значения с использованием +
Я часто задавался этим вопросом, есть ли стоимость исполнения для разделения строки на несколько строк, чтобы повысить читаемость при первоначальном присвоении значения строке. Я знаю, что строки неизменяемы, и поэтому каждую строчку нужно создавать каждый раз. Кроме того, стоимость исполнения фактически не имеет значения благодаря сегодняшнему действительно быстрому оборудованию (если вы не находитесь в какой-то дьявольской петле). Так, например:
String newString = "This is a really long long long long long" +
" long long long long long long long long long long long long " +
" long long long long long long long long long string for example.";
Как обрабатывает JVM или .Net компилятор и другие оптимизации. Будет ли она создавать одну строку? Или он будет создавать 1 строку, затем новую конкатенацию значения, а затем еще одну конкатенацию значений снова?
Это для моего собственного любопытства.
Ответы
Ответ 1
Это гарантируется спецификацией С#, чтобы быть идентичным созданию строки в одном литерале, потому что это константа времени компиляции. Из раздела 7.18 спецификации С# 3:
Всякий раз, когда выражение выполняет требования, перечисленные выше, выражение оценивается в время компиляции. Это справедливо, даже если выражение является подвыражением более крупное выражение, содержащее непостоянные конструкции.
(см. спецификацию для получения точной информации о "перечисленных выше требованиях":)
Спецификация языка Java указывает его в нижней части раздел 3.10.5:
Строки, вычисленные константой выражения (§15.28) вычисляются в компилировать время, а затем обрабатывать, как если бы они были литералами.
Ответ 2
В самом деле, в Java компилятор превратит String
в константу.
class LongLongString
{
public LongLongString()
{
String newString = "This is a really long long long long long" +
" long long long long long long long long long long long long " +
" long long long long long long long long long string for example.";
}
public static void main(String[] args)
{
new LongLongString();
}
}
Скомпилирован в:
Compiled from "LongLongString.java"
class LongLongString extends java.lang.Object{
public LongLongString();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: ldc #2; //String This is a really long long long long long long long long long long long long long long long long long long long long long long long long long long string for example.
6: astore_1
7: return
public static void main(java.lang.String[]);
Code:
0: new #3; //class LongLongString
3: dup
4: invokespecial #4; //Method "<init>":()V
7: pop
8: return
}
Как видно, одна строка загружается в строку 4, а не несколько экземпляров String
, которые загружаются.
Изменить: Исходный файл был скомпилирован с использованием javac
версии 1.6.0_06. Глядя на Спецификация языка Java, третье издание (и тот же раздел, упомянутый в Jon Skeet answer), мне не удалось найти ссылку на то, должен ли компилятор конкатенировать многострочный String
в один String
, поэтому это поведение, вероятно, зависит от реализации компилятора.
Ответ 3
Проверьте это для себя. В коде С# (эквивалент Java тоже будет работать):
string x = "A" + "B" + "C";
string y = "ABC";
bool same = object.ReferenceEquals(x, y); // true
Вы увидите, что результат true
.
В стороне, вы увидите, что строка также интернирована в пуле строк выполнения:
bool interned = object.ReferenceEquals(x, string.Intern(x)); // true
Ответ 4
Нет компрометации производительности. Оптимизация компилятора объединит это в одну строку (по крайней мере, на Java).
Ответ 5
Насколько я помню, это не создаст несколько строк, только один.
Ответ 6
Эквивалентный .NET IL для дополнения ответа coobird:
Для кода С#:
string s = "This is a really long long long long long" +
" long long long long long long long long long long long long " +
" long long long long long long long long long string for example.";
Console.WriteLine(s);
Отладочная компиляция дает:
.method public hidebysig static void Main(string[] args) cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.maxstack 1
.locals init (
[0] string str)
L_0000: ldstr "This is a really long long long long long long long long long long long long long long long long long long long long long long long long long long string for example."
L_0005: stloc.0
L_0006: ldloc.0
L_0007: call void [mscorlib]System.Console::WriteLine(string)
L_000c: ret
}
Итак, как вы можете видеть, это одна строка.
Ответ 7
Пока все строки являются постоянными (как в вашем примере), в Java (и я думаю, С#) компилятор преобразует это в одну строку.
Вы получаете только проблемы с производительностью с +, если вы объединяете много динамических строк, например, в цикле. В этом случае используйте StringBuilder или StringBuffer.
Ответ 8
Отказ от ответственности: это справедливо для Java. Я бы предположил, что это верно для С#
Не только javac создаст одну String, но JVM будет использовать одну String для всех остальных String, которые содержат один и тот же текст.
String a = "He" + "llo th"+ "ere";
String b = "Hell" + "o the"+ "re";
String c = "Hello" +" "+"there";
assert a == b; // these are the same String object.
assert a == c; // these are the same String object.
Примечание: они будут тем же объектом String во время выполнения, даже если они находятся в разных классах в разных JARS, скомпилированных разными компиляторами.