Почему в Java вы можете добавлять строки с помощью оператора +, если String - это класс? В String.javaкоде я не нашел реализации для этого оператора. Нарушает ли эта концепция объектную ориентацию?
Почему в Java вы можете добавлять строки с помощью оператора +, если String - это класс? В String.javaкоде я не нашел реализации для этого оператора. Нарушает ли эта концепция объектную ориентацию?
Ответы:
Давайте посмотрим на следующие простые выражения в Java
int x=15;
String temp="x = "+x;
Компилятор внутренне преобразует его "x = "+x;в StringBuilderи использует .append(int)для «добавления» целого числа к строке.
Любой тип может быть преобразован в тип String путем преобразования строки.
Значение x примитивного типа T сначала преобразуется в ссылочное значение, как если бы оно передавалось в качестве аргумента соответствующему выражению создания экземпляра класса (§15.9):
- Если T является логическим, используйте new Boolean (x).
- Если T - char, используйте новый символ (x).
- Если T является байтовым, коротким или целым числом, используйте новое целое число (x).
- Если T длинный, используйте новый Long (x).
- Если T - float, используйте новый Float (x).
- Если T - double, используйте новый Double (x).
Это ссылочное значение затем преобразуется в тип String путем преобразования строки.
Теперь нужно учитывать только справочные значения:
- Если ссылка пустая, она преобразуется в строку «null» (четыре символа ASCII n, u, l, l).
- В противном случае преобразование выполняется, как если бы путем вызова метода toString указанного объекта без аргументов; но если результатом вызова метода toString является null, вместо этого используется строка «null».
Метод toString определяется первичным классом Object (§4.3.2). Многие классы переопределяют его, особенно Boolean, Character, Integer, Long, Float, Double и String.
См. §5.4 для деталей контекста преобразования строки.
Оптимизация конкатенации строк: реализация может выбрать выполнение преобразования и конкатенации за один шаг, чтобы избежать создания и последующего удаления промежуточного объекта String. Чтобы повысить производительность повторяющейся конкатенации строк, компилятор Java может использовать класс StringBuffer или аналогичный метод, чтобы уменьшить количество промежуточных объектов String, которые создаются путем оценки выражения.
Для примитивных типов реализация может также оптимизировать создание объекта-оболочки путем прямого преобразования из примитивного типа в строку.
Оптимизированная версия фактически не выполняет сначала полное преобразование строки в оболочку.
Это хорошая иллюстрация оптимизированной версии, используемой компилятором, хотя и без преобразования примитива, где вы можете увидеть, как компилятор меняет вещи в StringBuilder в фоновом режиме:
http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/
Этот код Java:
public static void main(String[] args) {
String cip = "cip";
String ciop = "ciop";
String plus = cip + ciop;
String build = new StringBuilder(cip).append(ciop).toString();
}
Создает это - посмотрите, как два стиля конкатенации приводят к одному и тому же байт-коду:
L0
LINENUMBER 23 L0
LDC "cip"
ASTORE 1
L1
LINENUMBER 24 L1
LDC "ciop"
ASTORE 2
// cip + ciop
L2
LINENUMBER 25 L2
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 3
// new StringBuilder(cip).append(ciop).toString()
L3
LINENUMBER 26 L3
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 4
L4
LINENUMBER 27 L4
RETURN
Глядя на приведенный выше пример и на то, как генерируется байтовый код на основе исходного кода в данном примере, вы сможете заметить, что компилятор внутренне преобразовал следующий оператор
cip+ciop;
в
new StringBuilder(cip).append(ciop).toString();
Другими словами, оператор +конкатенации строк фактически является сокращением более подробной StringBuilderидиомы.
Это функция компилятора Java, которая проверяет операнды +оператора. И на основе операндов генерирует байт-код:
Вот что говорится в спецификации Java :
Операторы + и
-называются аддитивными операторами. AdditiveExpression: Мультипликативное выражение AdditiveExpression + Мультипликативное выражение AdditiveExpression - Мультипликативное выражениеАддитивные операторы имеют такой же приоритет и синтаксически ассоциативны слева (они группируются слева направо). Если тип любого из операндов
+оператора -Stringэто конкатенация строк.В противном случае тип каждого из операндов
+оператора должен быть типом, который может быть преобразован (§5.1.8) в примитивный числовой тип, в противном случае возникает ошибка времени компиляции.В любом случае тип каждого из операндов бинарного
-оператора должен быть типом, который может быть преобразован (§5.1.8) в примитивный числовой тип, в противном случае возникает ошибка времени компиляции.
Как класс String отменяет оператор +?
Это не так. Компилятор это делает. Строго говоря, компилятор перегружает оператор + для строковых операндов.
Прежде всего (+) перегружено, а не отменено
В языке Java предусмотрена специальная поддержка оператора конкатенации строк (+), который был перегружен для объектов Java Strings.
Если левый операнд - String, он работает как конкатенация.
Если левый операнд - целое число, он работает как оператор сложения
intи тогда применяются обычные правила Java.
В языке Java предусмотрена специальная поддержка оператора конкатенации строк (+) и преобразования других объектов в строки. Объединение строк осуществляется через класс StringBuilder(или StringBuffer) и его appendметод.
Значение +оператора в применении к нему Stringопределяется языком, как все уже написали. Поскольку вы не находите это достаточно убедительным, примите во внимание следующее:
Ints, float и doubles имеют разные двоичные представления, и поэтому добавление двух int - это другая операция с точки зрения манипуляции с битами, чем добавление двух чисел с плавающей запятой: для int вы можете добавлять бит за битом, переносить бит и проверять переполнение; для поплавков вы должны иметь дело с мантиссами и экспонентами отдельно.
Итак, в принципе, «добавление» зависит от природы «добавляемых» объектов. Java определяет его для строк, а также для целых чисел и чисел с плавающей запятой (длинные, двойные, ...)
Во время компиляции +оператор обычно заменяется StringBuilderна. Проверьте этот ответ, чтобы узнать больше об этом.
+оператор не заменяется на StringBuilder?
+Оператор Plus ( ) - это языковая функция Java.