Вопрос-ответ

How does the String class override the + operator?

Как класс String переопределяет оператор +?

Почему в Java вы можете добавлять строки с помощью оператора +, когда String является классом? ВString.java коде я не нашел никакой реализации для этого оператора. Нарушает ли эта концепция объектную ориентацию?

Переведено автоматически
Ответ 1

Давайте рассмотрим следующие простые выражения в Java

int x=15;
String temp="x = "+x;

Компилятор преобразует "x = "+x; в StringBuilder внутренне и использует .append(int) для "добавления" целого числа к строке.

5.1.11. Преобразование строк


Любой тип может быть преобразован в тип String путем преобразования строки.


Значение x примитивного типа T сначала преобразуется в ссылочное значение, как будто оно передается в качестве аргумента соответствующему выражению создания экземпляра класса (§15.9):



  • Если T - логическое значение, то используйте new Boolean(x).

  • Если T равно char, то используйте новый символ (x).

  • Если T равно byte, short или int, то используйте новое целое число (x).

  • Если T имеет значение long, то используйте new Long(x).

  • Если T равно float, то используйте new Float(x).

  • Если T равно double, то используйте new Double(x).


Затем это ссылочное значение преобразуется в тип String путем преобразования строки.


Теперь необходимо учитывать только ссылочные значения:



  • Если ссылка равна нулю, она преобразуется в строку "null" (четыре символа ASCII n, u, l, l).

  • В противном случае преобразование выполняется как бы путем вызова метода toString объекта, на который ссылается ссылка, без аргументов; но если результатом вызова метода toString является null, то вместо него используется строка "null".


Метод toString определяется объектом исходного класса (§4.3.2) . Многие классы переопределяют его, в частности Boolean, Character, Integer, Long, Float, Double и String .


Подробнее о контексте преобразования строк см. в §5.4.


15.18.1.


Оптимизация конкатенации строк : Реализация может выбрать выполнение преобразования и конкатенации за один шаг, чтобы избежать создания и последующего удаления промежуточного объекта String. Чтобы повысить производительность повторяющейся конкатенации строк, компилятор Java может использовать класс StringBuffer или аналогичный метод для уменьшения количества промежуточных строковых объектов, которые создаются при вычислении выражения.


Для примитивных типов реализация может также оптимизировать создание объекта-оболочки путем преобразования непосредственно из примитивного типа в строку.


Оптимизированная версия на самом деле не будет сначала выполнять полное преобразование строки.

Это хорошая иллюстрация оптимизированной версии, используемой компилятором, хотя и без преобразования примитива, где вы можете видеть, как компилятор преобразует вещи в 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 идиомы.

Ответ 2

Это функция компилятора Java, которая проверяет операнды + operator . И на основе операндов генерирует байтовый код:


  • Для String он генерирует код для объединения строк

  • Для Numbers он генерирует код для добавления чисел.

Это то, что говорится в спецификации Java:


Операторы + и - называются аддитивными операторами. Аддитивное выражение: Мультипликативное выражение AdditiveExpression + Мультипликативное выражение AdditiveExpression - мультипликативное выражение


Аддитивные операторы имеют одинаковый приоритет и синтаксически являются левоассоциативными (они группируются слева направо). Если тип любого из операндов + оператора String, то операция является конкатенацией строк.


В противном случае тип каждого из операндов оператора + должен быть типом, который можно преобразовать (§5.1.8) в примитивный числовой тип, иначе возникает ошибка времени компиляции.


В любом случае тип каждого из операндов двоичного - оператора должен быть типом, который можно преобразовать (§5.1.8) в примитивный числовой тип, иначе возникает ошибка времени компиляции.


Ответ 3

Как класс String переопределяет оператор +?


Это не так. Это делает компилятор. Строго говоря, компилятор перегружает оператор + для строковых операндов.

Ответ 4

Во-первых, (+) перегружен, а не переопределен


Язык Java предоставляет специальную поддержку оператора конкатенации строк (+), который был перегружен для объектов Java Strings.



  1. Если левый операнд является строковым, это работает как конкатенация.


  2. Если левый операнд является целым числом, он работает как оператор сложения


2024-02-29 13:56 java string