Java Casting: il compilatore è sbagliato o le specifiche linguistiche sono sbagliate o sbaglio?

StackOverflow https://stackoverflow.com/questions/5385743

  •  28-10-2019
  •  | 
  •  

Domanda

Ho letto The Java Language Spec, 3a edizione, e ho trovato quella che penso sia una discrepanza tra le specifiche e l'implementazione del compilatore Javac. Le stesse discrepanze esistono nel compilatore Eclipse.

Sezione 15.16 Parla di espressioni cast. Dice che dovrebbe essere un errore di tempo di compilazione se il tipo di argomento non può essere convertito nel tipo di cast tramite la conversione del casting (Sezione 5.5):

È un errore a tempo di compilazione se il tipo a tempo di compilazione dell'operando non può mai essere lanciato sul tipo specificato dall'operatore del cast secondo le regole di conversione del casting (§5.5). In caso contrario, a tempo di esecuzione, il valore dell'operimento viene convertito (se necessario) lanciando la conversione nel tipo specificato dall'operatore di cast.

Sezione 5.5 Parla della conversione del casting. Fornisce un elenco di tipi di conversione consentiti. In particolare dall'elenco è "la conversione di unboxing seguita da una conversione primitiva allargata/restringente". Tuttavia Quella sequenza esatta di conversioni sembra essere consentita dal compilatore Javac (e anche dal compilatore Eclipse). Per esempio:

long l = (long) Integer.valueOf(45);

... Compila bene. (Il cast problematico è il cast a long; L'argomento è di tipo java.lang.Integer, quindi la conversione richiede unboxing a int seguito da una conversione primitiva allargata).

Allo stesso modo, secondo il JLS non dovrebbe essere possibile lanciare byte a char, perché quello (secondo 5.1.4) richiede una conversione primitiva allargata e Una conversione primitiva restringente - tuttavia, questo cast è consentito anche dai compilatori.

Qualcuno può illuminarmi?

Modificare: Da quando ho chiesto questo, ho presentato un file riportare un errore con Oracle. La loro risposta è che questo è un "problema tecnico nel JLS".

È stato utile?

Soluzione

Penso che tu abbia ragione, i compilatori hanno ragione e le specifiche sono sbagliate ...

Questo compila: (Object)45 E questo no: (Long)45

L'unico modo per dare un senso al comportamento dei compilatori (incluso Intellij che sto usando) è se la conversione del casting viene modificata per concordare con la conversione dell'assegnazione e la conversione dell'invocazione del metodo:

  • Una conversione di boxe (§5.1.7) facoltativamente seguita da una conversione di riferimento allargata

  • Una conversione di unboxing (§5.1.8) facoltativamente seguita da una conversione primitiva allargata.

più

  • allargando e restringendo la conversione primitiva

La specifica ha detto che "le conversioni di casting sono più inclusive delle conversioni di invocazione di assegnazione o metodo: un cast può eseguire qualsiasi conversione consentita diversa da una conversione di stringa o una conversione di acquisizione"

Altri suggerimenti

Dalla mia lettura, il cast di int a long è consentito da questa clausola:

Un valore di un tipo primitivo può essere lanciato su un altro tipo primitivo mediante conversione di identità, se i tipi sono uguali o mediante una conversione primitiva allargata o una conversione primitiva restringente.

Convertire int a long è un allargando la conversione primitiva.

Che lascia solo la conversione da Integer a int, che è ospitato dall'ultimo proiettile:

Una conversione di unboxing

Certo, il cast a long non è nemmeno necessario nell'esempio.

Considera le seguenti quattro definizioni:

final Integer io = Integer.valueOf(45);
final int i = io;
final long l1 = (long)i;
final long l2 = i;

Consideri qualcuno di loro sorprendente? Il tuo esempio originale non sembra diverso; Elimina semplicemente le variabili intermedie.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top