Как осуществляется конкатенация строк в Java 9?
как написано в JEP 280:
изменить статический!--0-->-последовательность байт-кода конкатенации, генерируемая
javac
использоватьinvokedynamic
вызовы функций библиотеки JDK. Это позволит в будущем оптимизироватьString
конкатенация без необходимости внесения дополнительных изменений в байт-код, выдаваемыйjavac
.
здесь я хочу понять, в чем польза invokedynamic
вызовы и как конкатенация байт-кода отличается от invokedynamic
?
3 ответа:
"старый" способ вывода куча
StringBuilder
-ориентированные операции. Рассмотрим эту программу:public class Example { public static void main(String[] args) { String result = args[0] + "-" + args[1] + "-" + args[2]; System.out.println(result); } }
если мы скомпилируем это с JDK 8 или ранее, а затем используем
javap -c Example
посмотреть байт-код, мы видим что-то вроде этого:public class Example { public Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class java/lang/StringBuilder 3: dup 4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V 7: aload_0 8: iconst_0 9: aaload 10: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 13: ldc #5 // String - 15: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 18: aload_0 19: iconst_1 20: aaload 21: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: ldc #5 // String - 26: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 29: aload_0 30: iconst_2 31: aaload 32: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 35: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 38: astore_1 39: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 42: aload_1 43: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 46: return }как вы можете видеть, он создает
StringBuilder
и используетappend
. Это известно довольно неэффективно, так как емкость по умолчанию встроенного буфера вStringBuilder
- это только 16 символов, и нет никакого способа для компилятор знать выделите больше заранее, так что в конечном итоге придется перераспределить. Это также куча вызовов методов. (Обратите внимание, что JVM может иногда обнаружить и переписать эти шаблоны вызовов, чтобы сделать их более эффективными,.)давайте посмотрим, что генерирует Java 9:
public class Example { public Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: aload_0 1: iconst_0 2: aaload 3: aload_0 4: iconst_1 5: aaload 6: aload_0 7: iconst_2 8: aaload 9: invokedynamic #2, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 14: astore_1 15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 18: aload_1 19: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 22: return }О боже, Но это короче. :- ) Он делает один вызов
makeConcatWithConstants
СStringConcatFactory
, который говорит это в своем Javadoc:методы для облегчения создание методов конкатенации строк, которые могут быть использованы для эффективного конкатенации известного числа аргументов известных типов, возможно после адаптации типа и частичной оценки аргументов. Эти методы обычно используются как методы начальной загрузки на
invokedynamic
вызовите сайты, чтобы поддержать конкатенация строк особенность языка программирования Java.
прежде чем вдаваться в подробности
invokedynamic
реализация, используемая для оптимизации конкатенации строк, на мой взгляд, нужно получить некоторый фон над что такое invokedynamic и как его использовать?в
invokedynamic
инструкция упрощает и потенциально улучшает реализаций компиляторы и системы выполнения для динамических языков на JVM. Оно это позволяет средство реализации языка для определения пользовательского поведение связи сinvokedynamic
инструкция, которая включает в себя выполните следующие действия.
Я бы, вероятно, попытался провести вас через них с изменениями, которые были внесены для реализации оптимизации конкатенации строк.
определение метода начальной загрузки:- С Java9, методы начальной загрузки для
invokedynamic
места вызова, для поддержки конкатенация строк в первую очередьmakeConcat
иmakeConcatWithConstants
были введены сStringConcatFactory
реализация.использование invokedynamic предоставляет альтернативу для выбора стратегии перевода до времени выполнения. Стратегии перевода в
StringConcatFactory
похож наLambdaMetafactory
как представлено в предыдущей версии java. Кроме того, одна из целей JEP упомянутый в вопросе заключается в том, чтобы растянуть эти стратегии дальше.Указание Постоянных Записей Пула:- это дополнительные статические аргументы к
invokedynamic
обучения (1)MethodHandles.Lookup
объект, который является фабрикой для создания дескрипторов метода в контекстеinvokedynamic
инструкция, (2) aString
объект, имя метода, упомянутое в сайте динамического вызова и (3)MethodType
Я немного добавлю здесь немного деталей. Основная часть, чтобы получить это, как выполняется конкатенация строк является решение времени выполнения, а не время компиляции один больше. Таким образом, он может измениться, что означает, что вы скомпилировали свой код один раз против java-9 и он может изменить базовую реализацию, как ему заблагорассудится, без необходимости повторной компиляции.
и второй момент заключается в том, что на данный момент есть
6 possible strategies for concatenation of String
:private enum Strategy { /** * Bytecode generator, calling into {@link java.lang.StringBuilder}. */ BC_SB, /** * Bytecode generator, calling into {@link java.lang.StringBuilder}; * but trying to estimate the required storage. */ BC_SB_SIZED, /** * Bytecode generator, calling into {@link java.lang.StringBuilder}; * but computing the required storage exactly. */ BC_SB_SIZED_EXACT, /** * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. * This strategy also tries to estimate the required storage. */ MH_SB_SIZED, /** * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. * This strategy also estimate the required storage exactly. */ MH_SB_SIZED_EXACT, /** * MethodHandle-based generator, that constructs its own byte[] array from * the arguments. It computes the required storage exactly. */ MH_INLINE_SIZED_EXACT }
вы можете выберите любой из них с помощью параметра:
-Djava.lang.invoke.stringConcat
. Обратите внимание, чтоStringBuilder
- это еще вариант.