При додаванні 'a' + 'b'
виходить 195. Вихідний тип даних char
чи int
?
При додаванні 'a' + 'b'
виходить 195. Вихідний тип даних char
чи int
?
Відповіді:
Результатом додавання символів Java, шортів або байтів Java є int :
Специфікація мови Java щодо двійкового числового просування :
- Якщо будь-який з операндів має еталонний тип, виконується перетворення розпакування (§5.1.8). Тоді:
- Якщо один з операндів має тип double, інший перетворюється на double.
- В іншому випадку, якщо будь-який операнд має тип float, інший перетворюється на float.
- В іншому випадку, якщо будь-який операнд має тип long, інший перетворюється на long.
- В іншому випадку обидва операнди перетворюються на тип int.
Але зверніть увагу, що там сказано про оператори складеного призначення (наприклад, + =) :
Результат двійкової операції перетворюється на тип лівої змінної ... і результат перетворення зберігається у змінній.
Наприклад:
char x = 1, y = 2;
x = x + y; // compile error: "possible loss of precision (found int, required char)"
x = (char)(x + y); // explicit cast back to char; OK
x += y; // compound operation-assignment; also OK
Одним із способів дізнатись тип результату, загалом, є передати його на об’єкт і запитати, що це за клас:
System.out.println(((Object)('a' + 'b')).getClass());
// outputs: class java.lang.Integer
Якщо вас цікавить продуктивність, зверніть увагу, що байт-код Java навіть не має спеціальних інструкцій з арифметики з меншими типами даних. Наприклад, для додавання є інструкції iadd
(для ints), ladd
(для longs), fadd
(для floats), dadd
(для парних), і все. Для імітації x += y
з меншими типами компілятор використовує, iadd
а потім обнуляє верхні байти int, використовуючи інструкцію типу i2c
("int to char"). Якщо власний центральний процесор має спеціальні інструкції щодо 1-байтових або 2-байтових даних, віртуальна машина Java повинна оптимізувати для цього під час роботи.
Якщо ви хочете об’єднати символи як рядок, а не інтерпретувати їх як числовий тип, існує безліч способів зробити це. Найпростішим є додавання порожнього рядка до виразу, оскільки додавання символу та рядка призводить до отримання рядка. Усі ці вирази призводять до рядка "ab"
:
'a' + "" + 'b'
"" + 'a' + 'b'
(це працює, тому що "" + 'a'
оцінюється спочатку; якщо б вони ""
були в кінці, то ви б отримали "195"
)new String(new char[] { 'a', 'b' })
new StringBuilder().append('a').append('b').toString()
String.format("%c%c", 'a', 'b')
Двійкові арифметичні операції над char
та byte
(і short
) сприяння int
- JLS 5.6.2.
Можливо, ви захочете вивчити наступні вислови щодо char
.
char c='A';
int i=c+1;
System.out.println("i = "+i);
Це цілком справедливо в Java і повертає 66
відповідне значення символу (Unicode) c+1
.
String temp="";
temp+=c;
System.out.println("temp = "+temp);
Це занадто справедливо в Java, і змінна типу String temp
автоматично приймає c
тип char і видає temp=A
на консолі.
Усі наступні твердження також діють у Java!
Integer intType=new Integer(c);
System.out.println("intType = "+intType);
Double doubleType=new Double(c);
System.out.println("doubleType = "+doubleType);
Float floatType=new Float(c);
System.out.println("floatType = "+floatType);
BigDecimal decimalType=new BigDecimal(c);
System.out.println("decimalType = "+decimalType);
Long longType=new Long(c);
System.out.println("longType = "+longType);
Незважаючи на те c
, що це тип char
, він може бути поставлений без помилок у відповідних конструкторах, і всі вищезазначені твердження розглядаються як дійсні твердження. Вони дають такі результати відповідно.
intType = 65
doubleType = 65.0
floatType = 65.0
decimalType = 65
longType =65
char
є примітивним числовим інтегральним типом і як такий підпорядковується всім правилам цих звірів, включаючи перетворення та підвищення. Вам доведеться прочитати про це, і JLS - одне з найкращих джерел для цього: конверсії та акції . Зокрема, прочитайте короткий розділ "5.1.2 Розширення примітивного перетворення".
Компілятор Java може інтерпретувати його як один із них.
Перевірте це, написавши програму та шукаючи помилки компілятора:
public static void main(String[] args) {
int result1 = 'a' + 'b';
char result2 = 'a' + 'b';
}
Якщо це символ, то перший рядок дасть мені помилку, а другий - ні. Якщо це int, то станеться навпаки.
Я скомпілював його і отримав ..... ПОМИЛОК НІ. Отже, Java приймає обидва.
Однак, коли я їх надрукував, я отримав:
int: 195
char: Ã
Що трапляється, коли ви робите:
char result2 = 'a' + 'b'
виконується неявне перетворення ("примітивне звуження перетворення" з int на char ).
Відповідно до бінарних правил просування , якщо жоден з операндів не є подвійним, плаваючим або довгим, обидва підвищуються до int. Однак я наполегливо раджу не розглядати тип char як числовий, що перешкоджає його цілі.
char
як числового значення цілком відповідає його цілі, саме тому JLS приділяє стільки багатослів'я такому використанню.
Поки ви вже маєте правильну відповідь (на яку посилається JLS), ось трохи коду, щоб перевірити, чи отримаєте ви int
при додаванні двох char
s.
public class CharAdditionTest
{
public static void main(String args[])
{
char a = 'a';
char b = 'b';
Object obj = a + b;
System.out.println(obj.getClass().getName());
}
}
Вихідний результат
java.lang.Integer
int
і Integer
це не одне і те ж. Більш переконливим підтвердженням полягає в спробі привласнити a + b
до int
змінної або char
змінною. Остання видає помилку компіляції, яка фактично говорить "ви не можете призначити int
a для char
".
char
представляється у вигляді Unicode
значень і де значення Unicode представлені \u
наступними Hexadecimal
значеннями.
Як будь-яка арифметична операція над char
значеннями, що просуваються до int
, так і результат 'a' + 'b'
обчислюється як
1.) Застосуйте Unicode
значення за відповідним char
використаннямUnicode Table
2.) Застосуйте перетворення з шістнадцяткового в десяткове, а потім виконайте операцію над Decimal
значеннями.
char Unicode Decimal
a 0061 97
b 0062 98 +
195
Приклад
0061
(0 * 16 3 ) + (0 * 16 2 ) + (6 * 16 1 ) + (1 * 16 0 )
(0 * 4096) + (0 * 256) + (6 * 16) + (1 * 1)
0 + 0 + 96 + 1 = 97
0062
(0 * 16 3 ) + (0 * 16 2 ) + (6 * 16 1 ) + (2 * 16 0 )
(0 * 4096) + (0 * 256) + (6 * 16) + (2 * 1)
0 + 0 + 96 + 2 = 98
Отже 97 + 98 = 195
Приклад 2
char Unicode Decimal
Ջ 054b 1355
À 00c0 192
--------
1547 +
1163 -
7 /
260160 *
11 %
Хоча відповідь Боана є правильною, існує ускладнення, яке стосується випадку константних виразів, коли вони з'являються в контексті призначення .
Розглянемо такі приклади:
char x = 'a' + 'b'; // OK
char y = 'a';
char z = y + 'b'; // Compilation error
Що відбувається? Вони означають одне і те ж, чи не так? І чому в першому прикладі правомірно присвоювати int
а char
?
Коли константний вираз з'являється в контексті присвоєння, компілятор Java обчислює значення виразу і перевіряє, чи перебуває воно в діапазоні типу, якому ви призначаєте. Якщо це так, то застосовується неявне звужувальне примітивне перетворення .
У першому прикладі 'a' + 'b'
це константний вираз, і його значення впишеться в a char
, тому компілятор дозволяє неявне звуження int
результату виразу до a char
.
У другому прикладі y
є змінною, тому y + 'b'
НЕ є постійним виразом. Отже, незважаючи на те, що Сліпий Фредді бачить, що значення буде відповідати, компілятор НЕ допускає неявного звуження, і ви отримуєте помилку компіляції, яка говорить, що int
неможливо присвоїти char
.
Є деякі інші застереження щодо того, коли в цьому контексті допускається неявне звуження примітивного перетворення ; дивіться JLS 5.2 та JLS 15.28 для отримання детальної інформації.
Останній детально пояснює вимоги до постійного виразу . Це може бути не те, що ви можете подумати. (Наприклад, просто оголошення y
як final
не допомагає.)
char
тоді значення'a' + 'b'
не було б,195
але'Ã'