Czy w Javie wynik dodania dwóch znaków jest int czy char?

81

Podczas dodawania 'a' + 'b'daje 195. Czy typ danych wyjściowych charczy int?

Pomarańczowy
źródło
3
Jeśli typ były charwówczas wartość 'a' + 'b'nie byłoby 195jednak'Ã'
Joren
1
Tutaj jest 195 - ideone.com, ale nie w Eclipse.
pomarańczowy
2
Czytałeś to z książki o algorytmach lol! Przyszedłem tu właśnie z powodu tego ćwiczenia;)
Jack Twain

Odpowiedzi:

133

Wynikiem dodania znaków, skrótów lub bajtów Java jest int :

Specyfikacja języka Java w promocji binarnych liczb liczbowych :

  • Jeśli którykolwiek z operandów jest typu referencyjnego, wykonywana jest konwersja po rozpakowaniu (§5.1.8). Następnie:
  • Jeśli jeden z operandów jest typu double, drugi jest konwertowany na double.
  • W przeciwnym razie, jeśli jeden z operandów jest typu float, drugi jest konwertowany na float.
  • W przeciwnym razie, jeśli jeden z operandów jest typu long, drugi jest konwertowany na long.
  • W przeciwnym razie oba operandy są konwertowane na typ int.

Ale zwróć uwagę, co mówi o operatorach przypisania złożonych (takich jak + =) :

Wynik operacji binarnej jest konwertowany na typ lewej zmiennej ... a wynik konwersji jest zapisywany w zmiennej.

Na przykład:

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

Jednym ze sposobów, aby dowiedzieć się, jaki jest typ wyniku, jest rzutowanie go na obiekt i zapytanie, jaka to klasa:

System.out.println(((Object)('a' + 'b')).getClass());
// outputs: class java.lang.Integer

Jeśli interesuje Cię wydajność, zwróć uwagę, że kod bajtowy Java nie ma nawet dedykowanych instrukcji arytmetycznych z mniejszymi typami danych. Na przykład w przypadku dodawania, istnieją instrukcje iadd(na int), ladd(na wyroby długie), fadd(dla pływaków), dadd(dla podwójnej), i to wszystko. Aby przeprowadzić symulację x += yz mniejszymi typami, kompilator użyje, iadda następnie wyzeruje górne bajty int, używając instrukcji takiej jak i2c(„int to char”). Jeśli natywny procesor ma dedykowane instrukcje dla danych 1-bajtowych lub 2-bajtowych, to maszyna wirtualna Java musi je zoptymalizować w czasie wykonywania.

Jeśli chcesz konkatenować znaki jako ciąg znaków, zamiast interpretować je jako typ liczbowy, istnieje wiele sposobów, aby to zrobić. Najłatwiej jest dodać pusty ciąg do wyrażenia, ponieważ dodanie znaku i ciągu daje w wyniku ciąg. Wszystkie te wyrażenia powodują powstanie ciągu "ab":

  • 'a' + "" + 'b'
  • "" + 'a' + 'b'(to działa, ponieważ "" + 'a'jest oceniane jako pierwsze; gdyby ""zamiast tego były na końcu, otrzymasz "195")
  • new String(new char[] { 'a', 'b' })
  • new StringBuilder().append('a').append('b').toString()
  • String.format("%c%c", 'a', 'b')
Boann
źródło
22

Binarne operacje arytmetyczne na chari byte(i short) promują do int- JLS 5.6.2.

Hot Licks
źródło
2
I jednoargumentowe operacje arytmetyczne.
Tom Hawtin - tackline
7

Możesz chcieć nauczyć się następujących wyrażeń na temat char.

char c='A';
int i=c+1;

System.out.println("i = "+i);

Jest to całkowicie poprawne w Javie i zwraca 66odpowiednią wartość znaku (Unicode) c+1.


String temp="";
temp+=c;
System.out.println("temp = "+temp);

Jest to zbyt poprawne w Javie, a zmienna typu String tempautomatycznie akceptuje ctyp char i generuje temp=Ana konsoli.


Wszystkie poniższe instrukcje obowiązują również w Javie!

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);

Chociaż cjest to typ char, można go podać bez błędów w odpowiednich konstruktorach, a wszystkie powyższe instrukcje są traktowane jako prawidłowe instrukcje. Dają odpowiednio następujące wyniki.

intType = 65
doubleType = 65.0
floatType = 65.0
decimalType = 65
longType =65

charjest prymitywnym liczbowym typem całkowitym i jako taki podlega wszystkim regułom tych bestii, łącznie z konwersjami i promocjami. Będziesz chciał poczytać o tym, a JLS jest jednym z najlepszych źródeł tego: Konwersje i promocje . W szczególności przeczytaj krótki fragment „5.1.2 Poszerzanie pierwotnej konwersji”.

Lew
źródło
3

Kompilator Java może zinterpretować to jako jeden z nich.

Sprawdź to pisząc program i szukając błędów kompilatora:

public static void main(String[] args) {
    int result1 = 'a' + 'b';
    char result2 = 'a' + 'b';
}

Jeśli jest to znak, w pierwszej linii pojawi się błąd, aw drugiej nie. Jeśli jest to int, stanie się odwrotnie.

Skompilowałem i nie otrzymałem ..... ŻADNYCH BŁĘDÓW. Tak więc Java akceptuje oba.

Jednak gdy je wydrukowałem, otrzymałem:

int: 195

char: Ã

Dzieje się tak, gdy:

char result2 = 'a' + 'b'

wykonywana jest niejawna konwersja („pierwotna konwersja zawężająca” z int na char ).

eboix
źródło
Dziwię się, że nie otrzymałeś ostrzeżenia kompilatora w drugim przypadku o możliwej utracie precyzji z powodu zawężenia.
Hot Licks
@eboix: napisałeś "kompilator automatycznie rzutuje na char lub int" [sic] ... Co nie jest poprawne, ponieważ int nie jest "rzutowany" na int, a przejście z int do char nie jest wywoływane „obsada”, ale „zawężająca prymitywna konwersja”; )
TacticalCoder
Tak. Tego też się spodziewałem. Właściwie napisałem część mojej odpowiedzi na ten temat przed utworzeniem programu, ale potem usunąłem ją, gdy zobaczyłem, że nie otrzymałem żadnych ostrzeżeń ani błędów.
eboix
@eboix: eh eh:) Zmieniłbym to, ale nie mam jeszcze 2 000 punktów reputacji, stąd mój komentarz zamiast edycji; )
TacticalCoder
Jeśli chcesz, @ user988052, mogę zmienić to z powrotem na to, co było i możesz to edytować, zdobywając punkty. Nadal możesz ją edytować, jeśli masz mniej niż 2000 punktów reputacji. Jedyną rzeczą jest to, że osoba, która opublikowała wpis, musi zaakceptować edycję. Zmienię go z powrotem teraz, abyś mógł zdobyć dwa punkty, które są twoje.
eboix
1

Zgodnie z regułami promocji binarnej , jeśli żaden z operandów nie jest podwójny, zmiennoprzecinkowy ani długi, oba są promowane do int. Jednak zdecydowanie odradzam traktowanie typu char jako liczbowego, bo to mija się z celem.

Siergiej Tachenov
źródło
1
Używanie charjako wartości liczbowej jest całkowicie zgodne z jego celem, dlatego JLS poświęca tak wiele słownictwa na takie użycie.
Lew Bloch
1

Chociaż masz już poprawną odpowiedź (przywoływaną w JLS), oto fragment kodu, aby sprawdzić, czy otrzymujesz odpowiedź intpodczas dodawania dwóch 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());
    }
}

Wynik jest

java.lang.Integer

Paweł
źródło
To nie jest przekonująca weryfikacja, ponieważ wrzuciłeś do miksu konwersję bokserską. Rodzaje inti Integerto nie to samo. Weryfikacja bardziej przekonujące jest próba przypisania a + bdo intzmiennej lub charzmiennej. Ten ostatni powoduje błąd kompilacji, który mówi, że w efekcie „nie można przypisać an intdo a char”.
Stephen C
0

charjest reprezentowany jako Unicodewartości i gdzie wartości Unicode są reprezentowane \uprzez Hexadecimalwartości.

Jak każda operacja arytmetyczna na charwartościach promowanych do int, więc wynik 'a' + 'b'jest obliczany jako

1.) Zastosuj Unicodewartości przy odpowiednim charużyciuUnicode Table

2.) Zastosuj konwersję Szesnastkowy na Dziesiętny, a następnie wykonaj operację na Decimalwartościach.

    char        Unicode      Decimal
     a           0061          97
     b           0062          98  +
                              195

Unicode To Decimal Converter

Przykład

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

W związku z tym 97 + 98 = 195


Przykład 2

char        Unicode      Decimal
 Ջ           054b         1355
 À           00c0          192 
                      --------
                          1547    +
                          1163    -
                             7    /
                        260160    *
                            11    %
Pavneet_Singh
źródło
Nie o to chodzi w pytaniu.
Stephen C
Do Twojej wiadomości, Moja szczegółowa odpowiedź na powyższy komentarz została usunięta przez mody, które wyjaśniały powód migracji mojej odpowiedzi z usuniętego posta. jeśli moja odpowiedź została usunięta, aby ukryć błędy moderacji SO, to czy możesz przynajmniej usunąć powyższy komentarz lub w jakiś sposób wskazać publiczność, abym nie musiał pisać kolejnego komentarza? pytania do modów SO
Pavneet_Singh
Podtrzymuję swój komentarz. Tak jak ci odpowiedziałem ... ale potem usunąłem ... powód, dla którego zamieściłeś to pytanie tutaj, nie zmienia faktu, że jest ono w 95% nie na temat pytania i 5% powtórzenia wcześniejszych odpowiedzi. Jeśli chcesz zachować wyniki zmarnowanego wysiłku, lepiej byłoby zapisać je na dysku twardym. Lub znajdź inne pytanie, dla którego jest to istotne.
Stephen C
Jeśli masz problemy z moderatorami, zgłoś je na meta.stackoverflow.com. I przedstaw dowody. Jedyne, co próbuję tutaj zrobić, to posprzątać >> to << Q&A.
Stephen C
Rozumiem twój pogląd, ale nie mogę zrozumieć faktu ignorowania szczegółów konwersji Unicode z przykładami, jako dodatkowej wartości, która może pomóc niektórym czytelnikom, więc chciałbym zachować tę odpowiedź (rozumiem, że nie jest to dla ciebie przydatne i wydaje się nie- temat). Unikam meta i podobnych miejsc, ponieważ nie jest łatwo robić takie rzeczy bez zasilania i wsparcia, co zajmuje dużo czasu, wysiłku. Wolę zachować wewnętrzny spokój, Panie.
Pavneet_Singh
0

Chociaż odpowiedź Boanna jest poprawna, istnieje komplikacja, która dotyczy przypadku wyrażeń stałych , które pojawiają się w kontekstach przypisań .

Rozważ następujące przykłady:

  char x = 'a' + 'b';   // OK

  char y = 'a';
  char z = y + 'b';     // Compilation error

Co się dzieje? Mają na myśli to samo, prawda? I dlaczego legalne jest przypisanie a intdochar w pierwszym przykładzie ?

Gdy stałe wyrażenie pojawia się w kontekście przypisania, kompilator Java oblicza wartość wyrażenia i sprawdza, czy mieści się ona w zakresie typu, do którego przypisujesz. Jeśli tak, jest stosowana niejawna konwersja pierwotna zawężająca .

  • W pierwszym przykładzie 'a' + 'b'jest wyrażeniem stałym, a jego wartość zmieści się w a char, więc kompilator umożliwia niejawne zawężenie intwyniku wyrażenia do a char.

  • W drugim przykładzie yjest zmienną, więc y + 'b'NIE jest wyrażeniem stałym. Więc nawet jeśli Blind Freddy widzi, że wartość będzie pasować, kompilator NIE zezwala na żadne niejawne zawężenie, a ty otrzymujesz błąd kompilacji mówiący, że intnie można przypisać pliku char.

Istnieją inne zastrzeżenia co do tego, kiedy w tym kontekście dozwolona jest niejawna, zawężająca konwersja pierwotna ; szczegółowe informacje znajdują się w JLS 5.2 i JLS 15.28 .

Ten ostatni szczegółowo wyjaśnia wymagania dotyczące stałej ekspresji . Może nie być tym, co myślisz. (Na przykład samo zadeklarowanie yjako finalnie pomaga).

Stephen C.
źródło