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ć?


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.


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”.


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.


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;

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.