Podczas dodawania 'a' + 'b'
daje 195. Czy typ danych wyjściowych char
czy int
?
Podczas dodawania 'a' + 'b'
daje 195. Czy typ danych wyjściowych char
czy int
?
Odpowiedzi:
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 += y
z mniejszymi typami, kompilator użyje, iadd
a 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')
Binarne operacje arytmetyczne na char
i byte
(i short
) promują do int
- JLS 5.6.2.
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 66
odpowiednią wartość znaku (Unicode) c+1
.
String temp="";
temp+=c;
System.out.println("temp = "+temp);
Jest to zbyt poprawne w Javie, a zmienna typu String temp
automatycznie akceptuje c
typ char i generuje temp=A
na 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ż c
jest 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
char
jest 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”.
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 ).
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.
char
jako wartości liczbowej jest całkowicie zgodne z jego celem, dlatego JLS poświęca tak wiele słownictwa na takie użycie.
Chociaż masz już poprawną odpowiedź (przywoływaną w JLS), oto fragment kodu, aby sprawdzić, czy otrzymujesz odpowiedź int
podczas dodawania dwóch 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());
}
}
Wynik jest
java.lang.Integer
int
i Integer
to nie to samo. Weryfikacja bardziej przekonujące jest próba przypisania a + b
do int
zmiennej lub char
zmiennej. Ten ostatni powoduje błąd kompilacji, który mówi, że w efekcie „nie można przypisać an int
do a char
”.
char
jest reprezentowany jako Unicode
wartości i gdzie wartości Unicode są reprezentowane \u
przez Hexadecimal
wartości.
Jak każda operacja arytmetyczna na char
wartościach promowanych do int
, więc wynik 'a' + 'b'
jest obliczany jako
1.) Zastosuj Unicode
wartości przy odpowiednim char
użyciuUnicode Table
2.) Zastosuj konwersję Szesnastkowy na Dziesiętny, a następnie wykonaj operację na Decimal
wartościach.
char Unicode Decimal
a 0061 97
b 0062 98 +
195
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 %
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 int
dochar
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 int
wyniku wyrażenia do a char
.
W drugim przykładzie y
jest 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 int
nie 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 y
jako final
nie pomaga).
char
wówczas wartość'a' + 'b'
nie byłoby195
jednak'Ã'