Давайте рассмотрим вопрос о строке в Java: разница между "ABC" + '/' и "ABC" + "/". Через этот пример мы можем практиковать использование Javap в инструментах JDK. Первоначальный вопрос заключается в следующем:
В чем разница между обработкой чертов/как персонажей или струн?
Один используется в качестве основного типа данных, а другой - строка объекта. Какова конкретная разница?
Будет ли более эффективно рассматривать его как персонажа?
String str = "abc" + '/';
и
String str = "abc" + "/";
1. Оптимизация компилятора
Прежде всего, вы должны знать, что два вышеупомянутых предложения имеют одинаковый эффект, потому что компилятор оптимизирует два вышеуказанных предложения в следующие:
String str = "abc/";
Мы можем доказать это через Javap. Для Javap мы можем ссылаться на «5 инструментов JDK, которые должен знать каждый разработчик Java». Сначала мы создаем класс: Stringone и заполняем следующий код в основном методе:
Stringone.javastring str1 = "abc" + '/'; string str2 = "abc" + "/"; system.out.println(str1 == str2);
Скомпилируйте и запустите, результат вывода верно. Далее, наш Javap запущен, введите следующую команду в командную строку:
javap -v -l stringone.class> stringone.s
Затем проверьте сгенерированный файл stringone.s. Вы обнаружите, что в нем есть несколько строк
Stringone.s #2 = string #20 // abc /....# 20 = utf8 abc/... 0: ldc #2 // string abc/2: store_13: ldc #2 // string abc/5: store_2
Объяснение: Str1 и STR2 относятся к строке «ABC/».
2. Используйте Javap для анализа различий
Теперь давайте изменим вопрос. В чем разница между методами StringAddString и StringAddchar в следующем коде?
Stringtwopublic static String StringAddString (String Str1, String Str2) {return str1 + str2;} public static String StringDchar (String str, char ch) {return str + ch;}На этот раз javap используется для декомпиляции, а некоторые содержимое сгенерированного файла следующим образом
Stringtwo.spublic java.lang.string stringaddstring (java.lang.string, java.lang.string); дескриптор: (ljava/lang/string; ljava/lang/string;) ljava/lang/string; Флаги: ACC_PUBLIC CODE: Stack = 2, локалы = 3, args_size = 3 0: новый #2 // класс Java/Lang/StringBuilder 3: DUP 4: Invokespecial #3 // Метод Java/Lang/StringBuilder. » Приложение: (ljava/lang/string;) ljava/lang/stringbuilder; 11: Aload_2 12: Invokevirtual #4 // Метод Java/Lang/StringBuilder. Приложение: (ljava/lang/string;) ljava/lang/stringbuilder; 15: InvokeVirtual #5 // Метод Java/Lang/StringBuilder. ToString :() ljava/lang/string; 18: areturnpublic java.lang.string stringaddchar (java.lang.string, char); дескриптор: (ljava/lang/string; c) ljava/lang/string; Флаги: ACC_PUBLIC CODE: Stack = 2, локалы = 3, args_size = 3 0: новый #2 // класс Java/Lang/StringBuilder 3: DUP 4: Invokespecial #3 // Метод Java/Lang/StringBuilder. " java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 11: iload_2 12: Invokevirtual #6 // Метод Java/lang/StringBuilder.append: (c) Ljava/lang/StringBuilder; 15: InvokeVirtual #5 // Метод java/lang/stringbuilder.tostring :() ljava/lang/string; 18: Аретерн
Теперь мы можем четко увидеть процесс выполнения этих двух методов:
stringAddsstring
Процедура stringAddchar такая же, как StringAddsstring, за исключением того, что когда метод приложения называется вторым раз, параметр StringAddString имеет тип строки, в то время как параметр stringAddchar имеет тип Char.
3. Метод Append (char) и приложение (String) Метод класса StringBuilder
Здесь нам просто нужно проверить исходный код напрямую (шахта - это исходный код, который поставляется с JDK1.8.0_60). Обратите внимание, что, хотя документ показывает, что StringBuilder наследует от объекта, от исходного кода, он унаследован от абстрактного класса AbstractStringBuilder. И метод добавления реализован AbstractStringBuilder.
AbstractStringBuilder.java
Public AbstractStringBuilder Append (char C) {eveRecapacityInternal (count + 1); // Убедитесь, что массив может приспособить значение+1 символа [count ++] = c; вернуть это;} public AbstractStringBuilder Append (String Str) {if (str == null) return appendNull (); int len = str.length (); EnsureCapacityInternal (Count + Len); str.getchars (0, len, значение, граф); // Скопировать массив символов в строке в массив символов этого количества объектов += len; вернуть это;}Остальные больше не будут опубликованы. String.getChars (int, int, char [], int) в конечном итоге зависит от общедоступной статической нативной void arraycopy (Object, int, Object, int, int). Другими словами, это может быть написано на языке C, и эффективность должна быть лучше при копировании больших массивов, чем программы, написанные на Java. Итак, теперь позвольте мне рассказать вам, что я понимаю:
С точки зрения прямой памяти, поскольку строка содержит массивы char, массив должен иметь полей длины. В то же время класс строки обладает свойством int hash, и сам объект будет занимать дополнительную память для хранения другой информации, поэтому строка будет занимать больше памяти. Однако, если строка очень длинная, то эти накладные расходы на память могут быть почти игнорированы; И если строка (очень) короткая, очень вероятно, что существует много общих ссылок, чтобы поделиться этими накладными расходами на память, поэтому избыточные накладные расходы на память все еще можно игнорировать.
Из стека вызовов, поскольку строка имеет только один или два вызования функций, чем char, если здесь не рассматривается накладные расходы вызова функции (включая время и пространство), она должна быть аналогичной; Если рассматривается накладные расходы на вызов функции, «ABC» + '/' должен быть лучше; Но когда нужно подключено несколько символов (я думаю, что эта ситуация должна быть более распространенной, верно?), Поскольку для использования ChAR требуется много циклов для завершения соединения, количество вызванных функций будет только более вызвано, чем использование строки. В то же время копирование не будет быстрее, чем строка, непосредственно копируя массив. Таким образом, в настоящее время он становится «ABC» + »/» с большей пропускной способностью.
Теперь я чувствую, что этот вопрос задает: более ли эффективно использовать системные вызовы при чтении и написании файлов, или более эффективно использовать библиотеку IO в стандартной библиотеке функций. Я лично чувствую, что, хотя стандартная библиотека ввода-вывода должна вызовать системные вызовы в конце концов, и будут созданы некоторые временные переменные и более глубокие стеки вызовов из-за буферных механизмов библиотеки IO, пропускная способность библиотеки IO будет больше, а производительность в реальном времени будет лучше. Точно так же, хотя класс строки будет иметь больше полей и более глубокий стек функций, пропускная способность должна быть лучше из -за кэша и более прямого копирования.
Новые вопросы
Судя по приведенному приведенному коду декомпиляции Javap, когда две строки будут объединены вместе, они станут добавлением строк в StringBuilder. Итак, теоретически какой из следующих кодов более эффективен?
String str1 = "abc" + "123"; // 1StringBuilder stringBuilder = new StringBuilder (); // 2StringBuilder.Append ("abc"); stringBuilder.append ("123"); string str2 = stringBuilder.toString ();Пусть этот вопрос будет оставлен всем, чтобы подумать!
Выше всего содержимое этой статьи, которое помогает вам лучше отличить строку+строку и строку+char в Java. Я надеюсь, что это будет полезно для каждого обучения.