Masz jakiś pomysł, dlaczego muszę rzutować tutaj literał liczby całkowitej na (int)?


122

W poniższym przykładzie

int i = -128;
Integer i2 = (Integer) i; // compiles

Integer i3 = (Integer) -128; /*** Doesn't compile ***/

Integer i4 = (Integer) (int) -128; // compiles
Integer i4 = -128; // compiles
Integer i5 = (int) -128; // compiles
Integer i6 = (Integer) (-128); // compiles
Integer i7 = (Integer) 0-128; // compiles

Nie mogę rzucić -128z (Integer)ale mogę rzucić (int) -128.

Zawsze myślałem, że -128to inttyp i rzucanie go (int)powinno być zbędne.

Błąd w wierszu z i3to

cannot find symbol variable Integer

Próbowałem tego z aktualizacją Java 6 29 i aktualizacją Java 7 1.

EDYCJA: Otrzymujesz to samo zachowanie z +128zamiast -128. Wydaje się, że jest to zamieszanie między operatorami jednoargumentowymi i binarnymi.


5
jaki jest twój kompilator? Integer i = -128;to powinno się jednak skompilować.
bestsss

dziwne, Integer i3 = (Integer) (-128);chociaż się zgadza.
Eng. Fouad

2
@ Eng.Fouad, Peter, symbole jednoargumentowe (+ -) mają skojarzenie od prawej do lewej, a plus, minus są od lewej do prawej. Efekt -128 byłby taki sam jak +128 i wstawienie 0 z przodu powinno naprawić, tj. 0-128 lub 0 + 128. (nie mogę przetestować bankomatu, ale założę się, że tak będzie)
bestsss

Dobre pytanie! Osobiście chciałbym zobaczyć odniesienie JLS do rozwiązywania jednoargumentowych / binarnych operatorów i kiedy rzutowanie jest traktowane jako wyrażenie. W przeciwnym razie może się zdarzyć, że inne kompilatory nie uznają tego za błąd!
Bringer128

1
FYI również błąd, który otrzymuję w moim IDE, jest Expression expectedtam, gdzie Integerjest.
Bringer128

Odpowiedzi:


151

Kompilator próbuje odjąć 128od (Integer)zamiast rzutować -128do Integer. Dodaj, ()aby to naprawić

Integer i3 = (Integer) -128; // doesn't compile
Integer i3 = (Integer) (-128); // compiles

Według BoltClock w komentarzach odlew intdziała zgodnie z przeznaczeniem, ponieważ jest to słowo zastrzeżone i dlatego nie może być interpretowane jako identyfikator, co ma dla mnie sens.

Bringer128 znalazł JLS Reference 15.16 .

 CastExpression:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Jak widać, rzutowanie na typ pierwotny wymaga dowolnego UnaryExpression, podczas gdy rzutowanie na typ referencyjny wymaga pliku UnaryExpressionNotPlusMinus. Są one zdefiniowane tuż przed CastExpression w JLS 15.15 .


31
Myślę, że to dlatego, że intjest to słowo kluczowe w Javie, ale nim Integernie jest. Ponieważ intjest to słowo kluczowe, nie można go używać jako identyfikatora zmiennej lub klasy, pozostawiając jedyną pozostałą możliwość jako rzutowanie. To by to wyjaśniało.
BoltClock

@BoltClock Dołącz swój komentarz do odpowiedzi.
Jens Schauder

3
Aby uczynić tę odpowiedź jeszcze bardziej znakomitą, czy chcesz dodać mój link do JLS?
Bringer128

3
Interesującym (dla mnie) pomyłką w tej kwestii jest sposób rozwiązania analogicznego problemu w C #, który również ma niejednoznaczność w gramatyce między „wyrażeniem w nawiasach jako operandem do binarnego operatora odejmowania” i „operatorem rzutowania, gdzie właściwy operand rzut jest jednoargumentowym wyrażeniem minus ”. Zobacz sekcję 7.7.6 specyfikacji C #, aby uzyskać szczegółowy opis heurystyk, których używamy, aby sprytnie rozwiązać tę niejednoznaczność.
Eric Lippert

1
@BillK Dlaczego tak mówisz? Specyfikacja C # nie odnosi się do przeciążenia operatorów w sekcji 7.7.6, więc nie był to dla nich problem.
Bringer128

48

Znalazłem odniesienie do JLS. 15.16 .

 CastExpression:
    (PrimitiveType Dims optDims  ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Jak widać, rzutowanie na typ pierwotny wymaga dowolnego UnaryExpression, podczas gdy rzutowanie na typ referencyjny wymaga pliku UnaryExpressionNotPlusMinus. Są one zdefiniowane tuż przed CastExpression w JLS 15.15 .

Musisz albo zmienić rzutowanie na typ pierwotny:

... (int) -128;

Lub możesz zmienić wyrażenie po prawej stronie rzutowania na jednoargumentowe wyrażenie inne niż plus-minus:

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or

12

Kompilator interpretuje the -jako dwuargumentowy operator minus, tj. Próbuje odjąć 128 od innej wymienionej liczby Integer, ale nie ma takiej zmiennej w zakresie.

To kompiluje:

Integer i3 = (Integer) (-128)

Możesz dodać komentarz, dlaczego (int)ma znaczenie.
Peter Lawrey

1
To z powodu autoboxingu, prawda?
Brian Roach

9

Może to mieć związek z analizowaniem składni. Zauważ, że

Integer i4 = (Integer) (-128); 

działa dobrze.

Ogólnie rzecz biorąc, nie należy rzutować na klasę Integer. Wiąże się to z czymś, co nazywa się automatycznym boksowaniem i może powodować drobne błędy w kodzie. Preferowaną metodą robienia tego, co chcesz, jest:

Integer i6 = Integer.valueOf(-128)

1
rzut na Integer jest dokładnie syntetycznym cukrem dla valueOf.
bestsss

4
tak, ale czasami syntetyczny cukier zawodzi w subtelny sposób. Miałem kilka trudnych do wyśledzenia wyjątków zerowego wskaźnika w dużych aplikacjach ze względu na automatyczne boksowanie. Posunęliśmy się nawet do traktowania auto-boksu jako błędu, aby uniknąć bólów głowy w przyszłości. Magia jest fajna, ale kiedy zawodzi, bolą głowy. Uważam, że lepiej jest mówić wprost i oszczędzić sobie bólu głowy.
Krystian Cybulski

NPE to b1tch w / outboxing, prawda. Szczególnie w przypadkach for (int i in Collection<Integer>)b / c NPE znajduje się w absolutnie nieoczekiwanym miejscu. Właściwie nie używam liczby Integer z autoboxingiem, ponieważ zakres pamięci podręcznej jest mały (choć można go zwiększyć w opcji / XX), ale mam klasę o nazwie IntegerProvider (od 1.1), która robi to samo. Korzystanie z mapy (dowolne z java.util) Integer-> Cokolwiek jest zwykle hitem wydajnościowym, chyba że jest używane w trywialnych przypadkach i prawie zawsze istnieje lepsze rozwiązanie.
bestsss

Rzutowanie int na Integer nigdy nie może spowodować żadnych błędów, może z wyjątkiem przepełnienia sterty. Jednak odwrotność nie jest prawdą.
Ingo

@MattBall, nie do końca rozumiem, powszechnie używany jest cukier syntetyczny: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 i lepiej dla mnie brzmi syntetycznie.
bestsss

9

Przetwarza to jako Integer <minus operator> 128i nie znajduje zmiennej Integer. Będziesz musiał zawinąć -128w nawiasy:

Integer i3 = (Integer) (-128);  // compiles

Dałem +1 wszystkim innym odpowiedziom, ponieważ wszystkie też są poprawne :)
Bohemian

7
Integer i3 = (Integer) (-128);

Problem polega na tym, -że kompilator widzi to jako operator.


6

Linia 3 jest interpretowana tak, jakbyś próbował odjąć 128 od wyrażenia w nawiasie, a wyrażenie w nawiasie nie jest wyrażeniem typu int (traktuje „-” jako operator „-”). Jeśli zmienisz wyrażenie na:

Integer i3 = (Integer) (-128);

wtedy kompilator zrozumie, że „-” jest jednoargumentowym minusem, który wskazuje ujemną liczbę całkowitą.


3

Kompilator C # ma to samo zachowanie. Daje lepszą wskazówkę, dlaczego się nie kompiluje:

Aby rzutować wartość ujemną, musisz ująć wartość w nawiasach

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.