Dlaczego int i = 1024 * 1024 * 1024 * 1024 skompilować bez błędu?
Granica int
wynosi od -2147483648 do 2147483647.
If I input
int i = 2147483648;
Wtedy Eclipse wyświetli czerwone podkreślenie pod "2147483648".
Ale jeśli to zrobię:
int i = 1024 * 1024 * 1024 * 1024;
Będzie dobrze skompilowany.
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
Może to podstawowe pytanie w Javie, ale nie mam pojęcia, dlaczego drugi wariant nie powoduje błędu.
5 answers
Nie ma nic złego w tym stwierdzeniu; po prostu mnożysz 4 Liczby i przypisujesz je do int, tak się składa, że jest przepełnienie. Jest to co innego niż przypisanie pojedynczego literału , który byłby sprawdzany w czasie kompilacji.
To jest out-of-bounds literal powoduje błąd, a nie przypisanie :
System.out.println(2147483648); // error
System.out.println(2147483647 + 1); // no error
Dla kontrastu long
literal skompilowałby dobrze:
System.out.println(2147483648L); // no error
Zauważ, że w rzeczywistości wynik jest nadal obliczane w czasie kompilacji, ponieważ 1024 * 1024 * 1024 * 1024
jest wyrażenie stałe:
int i = 1024 * 1024 * 1024 * 1024;
Staje się:
0: iconst_0
1: istore_1
Zauważ, że wynik (0
) jest po prostu ładowany i przechowywany, i nie ma miejsca mnożenie.
Z JLS §3.10.1 (Dzięki @ ChrisK za poruszenie tego w komentarzach):
Jest to błąd w czasie kompilacji, jeśli literał dziesiętny typu
int
jest większy niż2147483648
(231), lub jeśli literał dziesiętny2147483648
pojawia się w dowolnym innym miejscu niż operand operatora unary minus (§15.15.4).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-14 23:30:44
1024 * 1024 * 1024 * 1024
i 2147483648
nie mają tej samej wartości w Javie.
Właściwie, 2147483648
nie jest nawet wartością(chociaż 2147483648L
jest) w Javie. Kompilator dosłownie nie wie, co to jest, ani jak z niego korzystać. Więc jęczy.
1024
jest poprawną wartością int w języku Java, a poprawna int
pomnożona przez inną poprawną int
jest zawsze poprawną int
. Nawet jeśli nie jest to ta sama wartość, której intuicyjnie oczekujesz, ponieważ obliczenia przepełnią się.
Przykład
Rozważ przykład kodu:
public static void main(String[] args) {
int a = 1024;
int b = a * a * a * a;
}
Czy spodziewasz się, że wygeneruje to błąd kompilacji? Teraz staje się trochę bardziej śliska.
Co zrobić, jeśli umieścimy pętlę z 3 iteracjami i pomnożony w pętli?
Kompilator może optymalizować, ale nie może zmienić zachowania programu w trakcie jego działania.
Kilka informacji o tym, jak ta sprawa jest faktycznie prowadzona:
W Javie i wielu innych językach liczby całkowite będą składać się ze stałej liczba bitów. Obliczenia, które nie mieszczą się w podanej liczbie bitów, będą przepełnione ; obliczenia są zasadniczo wykonywane moduł 2^32 w Javie, po czym wartość jest zamieniana z powrotem na signed integer.
Inne języki lub API używają dynamicznej liczby bitów (BigInteger
w Javie), wywołują wyjątek lub ustawiają wartość magiczną, taką jak not-a-number.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-16 18:13:47
Nie mam pojęcia, dlaczego drugi wariant nie powoduje błędu.
Zachowanie, które sugerujesz -- to jest Tworzenie komunikatu diagnostycznego, gdy obliczenia dają wartość większą niż największa wartość, która może być przechowywana w liczbie całkowitej -- jest funkcją . Aby korzystać z dowolnej funkcji, funkcja musi być pomyślana, uważana za dobry pomysł, zaprojektowana, określona, wdrożona, przetestowana, udokumentowana i wysłana do użytkowników.
Dla Javy, jedna lub więcej rzeczy na tej liście nie wydarzyło się, a zatem nie masz tej funkcji. Nie wiem który, trzeba by zapytać projektanta Javy.
Dla C#, wszystkie te rzeczy się wydarzyły-około czternaście lat temu-i tak odpowiedni program w C# wyprodukował błąd od C# 1.0.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-14 18:54:09
Oprócz odpowiedzi arszajii chcę pokazać jeszcze jedną rzecz:
To nieprzypisanie powoduje błąd, ale po prostu użycie dosłownego . Kiedy spróbujesz
long i = 2147483648;
Zauważysz, że powoduje również błąd kompilacji, ponieważ prawa strona nadal jest literalna int
i jest poza zasięgiem.
Więc operacje z int
- wartościami (i to łącznie z przypisaniami) mogą przepełnić się bez błędu kompilacji( i bez błędu runtime), ale kompilator nie radzi sobie z tymi zbyt dużymi literałami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-12 22:45:52
O: ponieważ to nie jest błąd.
Background: mnożenie 1024 * 1024 * 1024 * 1024
doprowadzi do przepełnienia. Przepełnienie jest bardzo często błędem. Różne języki programowania wytwarzają różne zachowania, gdy występują przepełnienia. Na przykład, C i C++ nazywają to "niezdefiniowanym zachowaniem" dla podpisanych liczb całkowitych, a zachowanie jest zdefiniowane jako niepodpisane liczby całkowite (weź wynik matematyczny, dodaj UINT_MAX + 1
tak długo, jak wynik jest ujemny, odjmij UINT_MAX + 1
tak długo, jak wynik jest większy niż UINT_MAX
).
W przypadku Javy, jeśli wynik operacji z wartościami int
nie mieści się w dozwolonym zakresie, koncepcyjnie Java dodaje lub odejmuje 2^32, dopóki wynik nie znajdzie się w dozwolonym zakresie. Tak więc oświadczenie jest całkowicie legalne i nie jest błędne. To po prostu nie daje rezultatu, na który możesz mieć nadzieję.
Możesz z pewnością argumentować, czy takie zachowanie jest pomocne i czy kompilator powinien dać ci Ostrzeżenie. Osobiście powiedziałbym, że Ostrzeżenie byłoby bardzo przydatne, ale błąd byłby nieprawidłowy, ponieważ jest to legalna Java.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-16 09:06:08