Veamos el código Java simple en el siguiente fragmento:
public class Main {
private int temp() {
return true ? null : 0;
// No compiler error - the compiler allows a return value of null
// in a method signature that returns an int.
}
private int same() {
if (true) {
return null;
// The same is not possible with if,
// and causes a compile-time error - incompatible types.
} else {
return 0;
}
}
public static void main(String[] args) {
Main m = new Main();
System.out.println(m.temp());
System.out.println(m.same());
}
}
En este código Java más simple, el temp()método no emite ningún error del compilador a pesar de que el tipo de retorno de la función es int, y estamos tratando de devolver el valor null(a través de la declaración return true ? null : 0;). Cuando se compila, esto obviamente causa la excepción de tiempo de ejecución NullPointerException.
Sin embargo, parece que lo mismo está mal si representamos el operador ternario con una ifdeclaración (como en el same()método), que hace emitir un error en tiempo de compilación! ¿Por qué?

int foo = (true ? null : 0)ynew Integer(null)ambos compilan bien, el segundo es la forma explícita de autoboxing.nullaInteger... Eso mismo aspecto que "adivinar" a mí o "hacer las cosas de trabajo" ...Integer foo() { return "1"; }no se compilará).Respuestas:
El compilador interpreta
nullcomo una referencia nula a unInteger, aplica las reglas de autoboxing / unboxing para el operador condicional (como se describe en la Especificación del lenguaje Java, 15.25 ), y continúa felizmente. Esto generará unNullPointerExceptiontiempo de ejecución, que puede confirmar probándolo.fuente
capture conversionylub(T1,T2)) ?? Además, ¿es realmente posible aplicar el boxeo a un valor nulo? ¿No sería esto como "adivinar"?lub(T1,T2)es el tipo de referencia más específico en común en la jerarquía de tipos de T1 y T2. (Ambos comparten al menos un Objeto, por lo que siempre hay un tipo de referencia más específico).nullno está encajonado en un entero, se interpreta como una referencia a un entero (una referencia nula, pero eso no es un problema). No se construye ningún objeto entero a partir del nulo, por lo que no hay razón para una NumberFormatException.null(que no es un tipo numérico primitivo), la cláusula aplicable es "Si p es un valor de cualquier otro tipo, la conversión de boxeo es equivalente a una conversión de identidad ". Entonces, la conversión del boxeonullaIntegerrendimientosnull, sin invocar a ningúnIntegerconstructor.Creo que el compilador de Java interpreta
true ? null : 0como unaIntegerexpresión, que se puede convertir implícitamenteint, posiblemente dandoNullPointerException.Para el segundo caso, la expresión
nulles del tipo nulo especial ver , por lo que el códigoreturn nullhace que el tipo no coincida.fuente
true ? null : 0comoInteger? Por autoboxing0primero ??En realidad, todo se explica en la Especificación del lenguaje Java .
Por lo tanto, el "nulo" en su
(true ? null : 0)obtiene un tipo int y luego se autoboxing a Integer.Pruebe algo como esto para verificar esto
(true ? null : null)y obtendrá el error del compilador.fuente
intvalor de la función, lo que provoca un NPE.nullaIntegerlanew Integer(null);"Let T1 sea del tipo que resulta de aplicar la conversión de boxeo a S1 ..." que se obtendría unaNumberFormatExceptiony esto no es el caso ...En el caso de la
ifdeclaración, lanullreferencia no se trata como unaIntegerreferencia porque no participa en una expresión que obliga a interpretarla como tal. Por lo tanto, el error puede detectarse fácilmente en tiempo de compilación porque es más claramente un error de tipo .En cuanto al operador condicional, la Especificación del lenguaje Java §15.25 "Operador condicional
? :" responde esto muy bien en las reglas sobre cómo se aplica la conversión de tipo:fuente
0está en caja automáticaInteger, el compilador está ejecutando el último caso de las "reglas de operador ternario" como se describe en la Especificación del lenguaje Java. Si eso es cierto, es difícil para mí creer que saltaría al caso 3 de las mismas reglas que tienen un tipo nulo y un tipo de referencia que hace que el valor de retorno del operador ternario sea el tipo de referencia (Entero). .Integer? Eso es exactamente lo que está sucediendo; el NPE se genera al tratar de desempaquetar el valor de la expresión para devolver un valorintde la función. Cambie la función para devolver unIntegery volveránullsin problema.nullse encuentre en esta categoría . Además, pasaríamos al paso "De lo contrario, se aplica la promoción numérica binaria (§5.6.2) ... Tenga en cuenta que la promoción numérica binaria realiza la conversión de desempaquetado (§5.1.8) ..." para determinar el tipo de retorno. Pero la conversión de unboxing generaría un NPE y esto ocurre solo en tiempo de ejecución y no mientras se intenta determinar el tipo de operador ternario. Todavía estoy confundido ..nullse trata como si tuviera tipoint, pero en realidad es equivalente athrow new NullPointerException(), eso es todo.Lo primero a tener en cuenta es que los operadores ternarios de Java tienen un "tipo", y que esto es lo que el compilador determinará y considerará sin importar cuáles sean los tipos reales / reales del segundo o tercer parámetro. Dependiendo de varios factores, el tipo de operador ternario se determina de diferentes maneras, como se ilustra en la Especificación del lenguaje Java 15.26
En la pregunta anterior deberíamos considerar el último caso:
Este es, con mucho, el caso más complejo una vez que echa un vistazo a la aplicación de la conversión de captura (§5.1.10) y, sobre todo, en lub (T1, T2) .
En inglés simple y después de una simplificación extrema, podemos describir el proceso como el cálculo de la "Superclase menos común" (sí, piense en el MCM) del segundo y tercer parámetro. Esto nos dará el operador "tipo" ternario. Nuevamente, lo que acabo de decir es una simplificación extrema (considere las clases que implementan múltiples interfaces comunes).
Por ejemplo, si intenta lo siguiente:
Notarás que el tipo resultante de la expresión condicional se debe a
java.util.Dateque es la "Superclase menos común" para elTimestamp/Timepar.Dado que
nullse puede autoboxear a cualquier cosa, la "Superclase menos común" es laIntegerclase y este será el tipo de retorno de la expresión condicional (operador ternario) anterior. El valor de retorno será entonces un puntero nulo de tipoIntegery eso es lo que devolverá el operador ternario.En tiempo de ejecución, cuando la máquina virtual de Java unboxes la
IntegerunaNullPointerExceptionse lanza. Esto sucede porque la JVM intenta invocar la funciónnull.intValue(), dondenulles el resultado del autoboxing.En mi opinión (y dado que mi opinión no está en la Especificación del lenguaje Java, muchas personas lo encontrarán mal de todos modos) el compilador hace un mal trabajo al evaluar la expresión en su pregunta. Dado que usted escribió,
true ? param1 : param2el compilador debe determinar de inmediato quenullse devolverá el primer parámetro - y generará un error de compilación. Esto es algo similar a cuando escribewhile(true){} etc...y el compilador se queja del código debajo del bucle y lo marcaUnreachable Statements.Su segundo caso es bastante sencillo y esta respuesta ya es demasiado larga ...;)
CORRECCIÓN:
Después de otro análisis, creo que me equivoqué al decir que un
nullvalor se puede encuadrar / encuadrar automáticamente en cualquier cosa. Hablando de la clase Integer, el boxeo explícito consiste en invocar alnew Integer(...)constructor o tal vez elInteger.valueOf(int i);(encontré esta versión en alguna parte). El primero arrojaría unNumberFormatException(y esto no sucede) mientras que el segundo simplemente no tendría sentido ya que unintno puede sernull...fuente
nullcódigo original en OP no está encuadrado. La forma en que funciona es: el compilador supone quenulles una referencia a un número entero. Usando las reglas para los tipos de expresiones ternarias, decide que la expresión completa es una expresión entera. Luego genera código para autobox el1(en caso de que la condición evalúefalse). Durante la ejecución, la condición se evalúa como, portruelo que la expresión se evalúa comonull. Al intentar devolver unintde la función, elnullestá sin caja. Eso luego arroja un NPE. (El compilador podría optimizar la mayor parte de esto.)En realidad, en el primer caso, la expresión se puede evaluar, ya que el compilador sabe que debe evaluarse como un
Integer; sin embargo, en el segundo caso, el tipo del valor de retorno (null) no se puede determinar, por lo que no se puede compilar. Si lo envíaInteger, el código se compilará.fuente
fuente
Qué tal esto:
La salida es verdadera, verdadera.
El color del eclipse codifica el 1 en la expresión condicional como autoboxed.
Supongo que el compilador está viendo el tipo de retorno de la expresión como Object.
fuente