Dlaczego „int i = 2147483647 + 1;” OK, ale „bajt b = 127 + 1;” nie jest kompilowalny?

126

Dlaczego jest int i = 2147483647 + 1;OK, ale byte b = 127 + 1;nie można go kompilować?

goku
źródło
16
Mam też szczerą wątpliwość: dlaczego bytetyp danych jest taki bolesny ?!
BoltClock
9
to zdecydowanie błąd projektowy, który bytejest podpisany zamiast niepodpisanego.
niezaprzeczalny
4
@BoltClock To ból tylko wtedy, gdy nie wiesz, jak go właściwie używać. stackoverflow.com/questions/397867/…
starblue
2
@starblue, czy istnieje przykład z życia wzięty, w którym można zastosować typ bajtu Java?
Thorbjørn Ravn Andersen
Jeśli istnieją dane, które są określone jako bajt, użyj języka Java bytedla przejrzystości, np. W parametrach. W takim przypadku fakt, że nie możesz przypisać intwartości, może nawet wyłapać pewne błędy. Lub użyj, byteaby zaoszczędzić miejsce w tablicach. Nie użyłbym bytedla pojedynczej wartości, która po prostu mieści się w bajcie.
starblue

Odpowiedzi:

172

Stałe są oceniane jako ints, więc 2147483647 + 1przepełniają i dają nowy int, który można przypisać do int, a 127 + 1jednocześnie jest oceniany jako intrówny 128i nie można go przypisać byte.

MByD
źródło
10
Właściwie dzisiaj przeczytałem kilka puzzlerów Java , w tym zagadkę właśnie o tym ... Zobacz tutaj: javapuzzlers.com/java-puzzlers-sampler.pdf - puzzle 3
MByD
3
Problem jest intzwiązany z binarną promocją liczbową, wartością 127jest czerwony śledź.
starblue
Wolałbym, aby stałe były oceniane z nieskończoną precyzją, dając również błąd int i = 2147483647 + 1;
Eduardo
@MByD: Jak powiedziałeś " while 127 + 1 also evaluated as int equals to 128, and it is not assignable to byte.", czy to oznacza, że ​​50 + 1 zostanie ocenione jako bytei dlatego można je przypisać do byte?
Bhushan
1
@ 10101010 - niezupełnie. będzie można go przypisać do bajtu, ale najpierw (zgodnie ze standardem) zostanie oszacowany jako int.
MByD
35

Literał 127 oznacza wartość typu int. Podobnie robi dosłowne 1. Suma tych dwóch jest liczbą całkowitą 128. Problem w drugim przypadku polega na tym, że przypisujesz to zmiennej typu bajt. Nie ma to nic wspólnego z rzeczywistą wartością wyrażeń. Ma to związek z tym, że Java nie obsługuje wymuszeń (*). Musisz dodać typecast

byte b = (byte)(127 + 1);

a potem się kompiluje.

(*) przynajmniej nie takiego rodzaju, jak łańcuch do liczby całkowitej, zmiennoprzecinkowy do czasu, ... Java obsługuje wymuszanie, jeśli w pewnym sensie nie powoduje utraty (Java nazywa to „poszerzaniem”).

I nie, słowo „przymus” nie wymagało poprawiania. Zostało to wybrane bardzo celowo i właściwie. Z najbliższego źródła (Wikipedia): „W większości języków słowo wymuszenie jest używane do określenia niejawnej konwersji podczas kompilacji lub w czasie wykonywania”. oraz „W informatyce konwersja typów, rzutowanie typów i wymuszanie są różnymi sposobami pośredniej lub jawnej zmiany jednostki jednego typu danych na inny”.

Erwin Smout
źródło
Twój przykładowy kod powinien prawdopodobnie mieć postać bajt b = (bajt) 127 + 1; czyli „Dodaj 1 do maksymalnej wartości bajtu”, Twój przykład po prostu zamienia wartość int równą 128 na wartość bajtową.
NKCSS
6
@NKCSS - nie sądzę, że masz rację, to - (byte)(127 + 1)rzut 128 (integer) na bajt, podczas gdy to (byte)127 + 1rzutuje 127 na bajt, ale potem znowu na int, ponieważ jest dodawany do 1 (int) i ty get 128 (int), a błąd pozostaje.
MByD
6

Jako dowód dla @MByD:

Następujący kod jest kompilowany:

byte c = (byte)(127 + 1);

Ponieważ chociaż wyrażenie (127 + 1)jest int i poza zakresem poza bytetypem, wynik jest rzutowany na byte. To wyrażenie tworzy -128.

AlexR
źródło
3

JLS3 # 5.2 Konwersja przypisania

(zmienna = wyrażenie)

Ponadto, jeśli wyrażenie jest wyrażeniem stałym (§15.28) typu byte, short, char lub int:

Zwężającą konwersję pierwotną można zastosować, jeśli typ zmiennej to bajt, krótka lub znak, a wartość wyrażenia stałego można przedstawić w typie zmiennej.


Bez tej klauzuli nie moglibyśmy pisać

byte x = 0;
char c = 0;

Ale czy powinniśmy być w stanie to zrobić? Nie sądzę. Wśród prymitywów zachodzi pewna magia, trzeba być bardzo ostrożnym. Zrobiłbym wszystko, żeby pisać

byte x = (byte)0;
nieoceniony
źródło
jeśli chodzi o pytanie, czy powinniśmy być w stanie ... nie widzę w tym nic złego, byte x = 0ale z drugiej strony jestem programistą C.
Grady Player
Być może mógłbym zobaczyć argument przeciwko char c = 0, ale dlaczego bajt x = 0 jest zły?
Michael Burge
To mylące dla niewprawnych oczu, myśląc, że przypisują bajt 0 do zmiennej bajtowej. W tym przykładzie niewiele szkodzi, ale ogólnie operowanie na bajt / krótki / znak może być bardzo mylące z powodu niejawnych konwersji. Są o wiele bardziej skomplikowane, niż mogłoby się wydawać. Chcę, aby mój kod był jak najbardziej przejrzysty, nie wprowadzaj żadnej niepewności ze względu na oszczędność kilku naciśnięć klawiszy.
niezaprzeczalny
Czy podobna zasada ma zastosowanie, gdy zawężająca konwersja pierwotna jest z long na int, np. Int i = 1 + 0L? Po prostu pytam, ponieważ cytowany tekst wyraźnie pomija ten przypadek.
Erwin Smout
@Erwin nie, int i=0Ljest nielegalne.
niezaprzeczalny