Чому в Java ви можете додати Strings з оператором +, коли String - клас? У String.java
коді я не знайшов жодної реалізації цього оператора. Чи порушує це поняття орієнтація на об'єкт?
Чому в Java ви можете додати Strings з оператором +, коли String - клас? У String.java
коді я не знайшов жодної реалізації цього оператора. Чи порушує це поняття орієнтація на об'єкт?
Відповіді:
Давайте розглянемо наступні прості вирази на Java
int x=15;
String temp="x = "+x;
Компілятор перетворюється "x = "+x;
у StringBuilder
внутрішньо і використовує .append(int)
для "додавання" цілого числа до рядка.
Будь-який тип може бути перетворений у тип String шляхом перетворення рядків.
Значення x примітивного типу T спочатку перетворюється на опорне значення так, ніби надаючи його як аргумент відповідному виразу створення екземпляра класу (§15.9):
- Якщо T булеве, використовуйте новий булевий (x).
- Якщо T - char, використовуйте новий символ (x).
- Якщо T - байт, короткий або int, використовуйте новий Integer (x).
- Якщо T довгий, то використовуйте новий Long (x).
- Якщо T є плаваючою, використовуйте новий Float (x).
- Якщо T подвійний, використовуйте новий Double (x).
Це опорне значення потім перетворюється у тип String шляхом перетворення рядків.
Тепер потрібно враховувати лише базові значення:
- Якщо посилання є нульовим, воно перетворюється на рядок "null" (чотири ASCII символи n, u, l, l).
- В іншому випадку перетворення виконується як би викликом методу toString посиланого об'єкта без аргументів; але якщо результат виклику методу toString є нульовим, то натомість використовується рядок "null".
Метод toString визначається початковим класом Object (§4.3.2). Багато класів переважають його, зокрема булева, персонажа, ціла, довга, плаваюча, подвійна та струнна.
Детальніше про контекст перетворення рядків див. У § 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: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpressionОператори добавок мають однаковий пріоритет і є синтаксично лівим асоціативом (вони групуються зліва направо). Якщо тип будь-якого операнда
+
оператора єString
, то операція є конкатенацією рядків.В іншому випадку тип кожного операнда
+
оператора повинен бути типом, який може бути конвертованим (§5.1.8) у примітивний числовий тип, або виникає помилка часу компіляції.У кожному випадку тип кожного операнда двійкового
-
оператора повинен бути типом, який може бути конвертованим (§5.1.8) у примітивний числовий тип, або виникає помилка часу компіляції.
Як клас String замінює + оператор?
Це не так. Укладач це робить. Строго кажучи, компілятор перевантажує оператор + для String операндів.
Насамперед (+) перевантажений, а не перекритий
Мова Java забезпечує спеціальну підтримку оператора конкатенації рядків (+), який був перевантажений для об'єктів Java Strings.
Якщо операнд лівої сторони - String, він працює як конкатенація.
Якщо операнд лівої сторони є Integer, він працює як оператор додавання
int
і тоді застосовуються звичайні правила Java.
Мова Java забезпечує спеціальну підтримку оператора конкатенації рядків (+) та для перетворення інших об'єктів у рядки. Зв'язування рядків реалізується через StringBuilder
(або StringBuffer
) клас та його append
метод.
Значення +
оператора при зверненні String
визначається мовою, як уже написали всі. Оскільки вам здається це не досить переконливим, врахуйте це:
Інти, поплавці та подвійні мають різні бінарні уявлення, і тому додавання двох int - це інша операція, з точки зору маніпулювання бітом, ніж додавання двох поплавків: Для ints ви можете додавати побіт, переносячи біт і перевіряючи на переповнення; для поплавців ви повинні мати справу з мантіями та експонентами окремо.
Отже, в принципі "додавання" залежить від природи об'єктів, що додаються. Java визначає його як для Strings, так і для ints та floats (longs, double, ...)
+
Оператор зазвичай замінений StringBuilder
під час компіляції. Перевірте цю відповідь, щоб отримати детальнішу інформацію з цього питання.
+
оператора не замінюють StringBuilder
?
+
Оператор Plus ( ) - це мовна особливість Java.