У Java результат додавання двох символів - це int або char?


81

При додаванні 'a' + 'b'виходить 195. Вихідний тип даних charчи int?


3
Якби тип був, charтоді значення 'a' + 'b'не було б, 195але'Ã'
Йорен

1
Тут 195 - ideone.com, але не в Eclipse.
помаранчевий

2
Ви читали це з книги "Алгоритми" ха-ха! Я прийшов сюди саме через цю вправу;)
Джек Твен,

Відповіді:


133

Результатом додавання символів 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')


7

Можливо, ви захочете вивчити наступні вислови щодо 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 Розширення примітивного перетворення".


3

Компілятор 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 ).


Я здивований, що у другому випадку ви не отримали попередження компілятора про можливу втрату точності через звуження.
Hot Licks

@eboix: ви написали "компілятор автоматично передає або char, або int" [sic] ... Що неправильно, оскільки int не "відливається" до int, а перехід від int до char не викликається "кидок", але "звуження примітивного перетворення"; )
TacticalCoder

Так. Я теж цього чекав. Я фактично написав про це частину своєї відповіді ще до того, як створити програму, але потім видалив її, коли побачив, що не отримав попереджень та помилок.
eboix

@eboix: eh eh :) Я б його відредагував, але ще не маю 2000 очок репутації, отже мій коментар замість редагування; )
TacticalCoder

Якщо ви хочете, @ user988052, я можу повернути його до того, що це було, і ви можете редагувати його, отримуючи бали. Ви все ще можете редагувати його, якщо у вас менше 2000 очок репутації. Єдине, що особа, яка зробила допис, повинна прийняти редагування. Зараз я поверну його назад, щоб ви могли отримати два пункти, які по праву належать вам.
eboix

1

Відповідно до бінарних правил просування , якщо жоден з операндів не є подвійним, плаваючим або довгим, обидва підвищуються до int. Однак я наполегливо раджу не розглядати тип char як числовий, що перешкоджає його цілі.


1
Використання charяк числового значення цілком відповідає його цілі, саме тому JLS приділяє стільки багатослів'я такому використанню.
Lew Bloch

1

Поки ви вже маєте правильну відповідь (на яку посилається JLS), ось трохи коду, щоб перевірити, чи отримаєте ви intпри додаванні двох chars.

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змінною. Остання видає помилку компіляції, яка фактично говорить "ви не можете призначити inta для char".
Стівен С,

0

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

Unicode To Decimal Converter

Приклад

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    %

Це не те, про що задається питання.
Стівен С,

FYI, Мою детальну відповідь на вищезазначений коментар було видалено модами, які пояснили причину перенесення моєї відповіді зі видаленого допису. якщо моя відповідь була видалена, щоб приховати недоліки модерації SO, чи можете ви принаймні видалити вищезазначений коментар або якось вказати аудиторію, щоб мені не довелося писати ще один коментар? питання до модів SO
Pavneet_Singh

Я дотримуюсь свого коментаря. Як я вам відповів ... але потім видалив ... причина того, що ви опублікували це запитання тут, не змінює той факт, що воно на 95% не відповідає питанню, і 5% повторення попередніх відповідей. Якщо ви хочете зберегти результати своїх марно витрачених зусиль, було б доцільніше зберегти їх на жорсткому диску. Або знайдіть якесь інше запитання, яке воно має відношення.
Стівен С

Якщо у вас є проблеми з модераторами, розгляньте це на meta.stackoverflow.com. І надати докази. Все, що я намагаюся зробити тут, - це привести в порядок >> це << Запитання та відповіді.
Стівен С

Я розумію вашу думку, але не можу зрозуміти факт ігнорування деталей перетворення Unicode на прикладах, як додаткове значення, яке може допомогти деяким читачам, тому я хотів би зберегти цю відповідь (я розумію, що це не корисно для вас і здається теми). Я уникаю мета та подібних місць, оскільки нелегко робити подібні речі без влади та підтримки, що вимагає багато часу, зусиль. Я вважаю за краще зберігати свій внутрішній спокій Сир.
Pavneet_Singh

0

Хоча відповідь Боана є правильною, існує ускладнення, яке стосується випадку константних виразів, коли вони з'являються в контексті призначення .

Розглянемо такі приклади:

  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не допомагає.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.