Do dzisiaj myślałem, że na przykład:
i += j;
Był tylko skrótem do:
i = i + j;
Ale jeśli spróbujemy:
int i = 5;
long j = 8;
Wtedy i = i + j;
nie będzie kompilować, ale i += j;
skompiluje dobrze.
Czy to oznacza, że tak naprawdę i += j;
jest skrót do czegoś takiego
i = (type of i) (i + j)
?
java
casting
operators
variable-assignment
assignment-operator
Honza Brabec
źródło
źródło
i+=(long)j;
nawet skompiluje się dobrze.i += (int) f;
rzuca f przed dodaniem, więc nie jest równoważne.(int) i += f;
rzutuje wynik po przypisaniu, również nie równoważny. nie byłoby miejsca na rzutowanie, które oznaczałoby, że chcesz rzutować wartość po dodaniu, ale przed przypisaniem.Odpowiedzi:
Jak zawsze w przypadku tych pytań, JLS posiada odpowiedź. W takim przypadku §15.26.2 Operatorzy przydziału złożonych . Ekstrakt:
Przykład cytowany w § 15.26.2
Innymi słowy, twoje założenie jest prawidłowe.
źródło
i+=j
kompiluje, jak sam sprawdzałem, ale spowodowałoby to utratę precyzji, prawda? Jeśli tak jest, dlaczego nie pozwala na to również w i = i + j? Po co nas tam wkurzać?i += j
), to bezpieczniej jest założyć, że pożądane jest utrata precyzji, w przeciwieństwie do drugiej sprawy (i = i + j
)E1 op= E2 is equivalent to E1 = (T)((E1) op (E2))
więc jest to coś w rodzaju niejawnego rzutowania w dół (z długiego na int). Podczas gdy w i = i + j musimy to zrobić jawnie, tj. Podać(T)
część wE1 = ((E1) op (E2))
Czy nie?Dobrym przykładem tego rzutowania jest użycie * = lub / =
lub
lub
lub
źródło
A
;)ch += 32
= DBardzo dobre pytanie. Specyfikacja języka Java potwierdza Twoją sugestię.
źródło
double->float
jako rozszerzenie, na podstawie tego, że wartości typufloat
identyfikują liczby rzeczywiste mniej konkretnie niż wartości typudouble
. Jeśli ktoś widzidouble
jako pełny adres pocztowy ifloat
jako 5-cyfrowy kod pocztowy, możliwe jest spełnienie żądania podania kodu pocztowego podanego pełnego adresu, ale nie jest możliwe dokładne określenie żądania pełnego adresu podanego tylko kodem pocztowym . Konwersja adresu ulicy na kod pocztowy jest operacjąfloat->double
jest równoznaczna z konwersją amerykańskiego kodu pocztowego 90210 na „US Post Office, Beverly Hills CA 90210”.Tak,
w zasadzie kiedy piszemy
kompilator konwertuje to na
Właśnie sprawdziłem
.class
kod pliku.Naprawdę dobrze wiedzieć
źródło
musisz rzutować od
long
do,int
explicitly
w przeciwnym raziei = i + l
skompiluje się i da poprawny wynik. lubićlub
ale w przypadku
+=
tego działa po prostu dobrze, ponieważ operator domyślnie wykonuje rzutowanie typu z typu prawej zmiennej na typ lewej zmiennej, więc nie trzeba jawnie rzutować.źródło
int
wykonywana jest po+
. Kompilator rzuciłby (powinien?) Ostrzeżenie, jeśli naprawdę rzuciłoby tolong
naint
.Problem dotyczy tutaj rzutowania na typy.
Kiedy dodasz int i long,
Ale
+=
jest zakodowany w taki sposób, że wykonuje rzutowanie.i=(int)(i+m)
źródło
W Javie konwersje typu są wykonywane automatycznie, gdy typ wyrażenia po prawej stronie operacji przypisania można bezpiecznie awansować do typu zmiennej po lewej stronie przypisania. W ten sposób możemy bezpiecznie przypisać:
To samo nie zadziała na odwrót. Na przykład nie możemy automatycznie przekonwertować długiego na int, ponieważ pierwszy wymaga więcej pamięci niż drugi, w wyniku czego informacje mogą zostać utracone. Aby wymusić taką konwersję, musimy przeprowadzić jawną konwersję.
Typ - konwersja
źródło
long
jest 2 razy większy niżfloat
.float
może pomieścić każdej możliwejint
wartości idouble
nie może pomieścić każdej możliwejlong
wartości.double d=33333333+1.0f;
bez zarzutu, choć wynik +33333332,0 nie może być to, co miało (nawiasem mówiąc, arytmetycznie-poprawna odpowiedź 33333334.0f byłoby reprezentowalna jako albofloat
alboint
).Czasami takie pytanie można zadać podczas wywiadu.
Na przykład podczas pisania:
nie ma automatycznego rzutowania tekstu. W C ++ nie będzie żadnego błędu przy kompilowaniu powyższego kodu, ale w Javie otrzymasz coś takiego
Incompatible type exception
.Aby tego uniknąć, musisz napisać swój kod w następujący sposób:
źródło
op
użycia w C ++ z użyciem w Javie. Zawsze lubię oglądać te drobiazgi i myślę, że wnoszą coś do rozmowy, co często można pominąć.Główną różnicą jest to, że z
a = a + b
nie odbywa się rzutowanie typu, a więc kompilator jest zły na ciebie za to, że nie masz rzutowania. Ale za += b
tym, co naprawdę robi, to rzutowanieb
na typ zgodny za
. Jeśli takTo, co naprawdę robisz, to:
źródło
Subtelny punkt tutaj ...
Istnieje domyślna typografia dla
i+j
kiedyj
jest podwójnym ii
int. Java ZAWSZE konwertuje liczbę całkowitą na podwójną, gdy między nimi jest operacja.Aby wyjaśnić,
i+=j
gdziei
jest liczba całkowita i liczbaj
podwójna, można opisać jakoZobacz: ten opis niejawnego castingu
Może chcesz typecast
j
aby(int)
w tym przypadku dla jasności.źródło
int someInt = 16777217; float someFloat = 0.0f; someInt += someFloat;
. Dodanie zera dosomeInt
nie powinno wpływać na jego wartość, ale promowaniesomeInt
dofloat
może zmienić jego wartość.Specyfikacja języka Java określa,
E1 op= E2
że jest równoważna z tym,E1 = (T) ((E1) op (E2))
gdzieT
jest typem,E1
iE1
jest oceniana raz .To techniczna odpowiedź, ale możesz się zastanawiać, dlaczego tak jest. Rozważmy następujący program.
Co drukuje ten program?
Zgadłeś 3? Szkoda, że ten program się nie skompiluje. Dlaczego? Tak się składa, że dodanie bajtów w Javie jest zdefiniowane w celu zwrócenia
int
. Wydaje mi się, że było tak dlatego, że wirtualna maszyna Java nie definiuje operacji bajtów, które mają być zapisywane na kodach bajtów (w końcu jest ich ograniczona liczba), użycie operacji na liczbach całkowitych jest szczegółem implementacji ujawnionym w języku.Ale jeśli
a = a + b
nie działa, to znaczyłoby,a += b
że nigdy by nie działało dla bajtów, gdybyE1 += E2
zostało zdefiniowane jakoE1 = E1 + E2
. Jak pokazuje poprzedni przykład, rzeczywiście tak by było. W celu włamania się+=
operatora do bajtów i skrótów zaangażowana jest ukryta obsada. Nie jest to świetny hack, ale już podczas pracy nad Javą 1.0 skupiono się na wydaniu języka na początek. Teraz, ze względu na kompatybilność wsteczną, tego hacka wprowadzonego w Javie 1.0 nie można było usunąć.źródło