¿Funciona== realmente igual o diferente al comparar dos primitivas frente a dos objetos en Java?
object primitive (2)
Al buscar explicaciones de cómo funciona el
==
lógico en Java, las respuestas siempre son algo similar a:
- Para las primitivas, devuelve si las primitivas tienen el mismo valor (esto incluye comparar una primitiva con su objeto WrapperObject, ya que el objeto WrapperObject se desempaqueta automáticamente a una primitiva).
- Para los objetos, devuelve si representan el mismo objeto en el montón.
Pero todas estas explicaciones parecen implicar que se trata de
2 cosas diferentes
, que
==
comporta de manera diferente dependiendo de si está comparando Objetos versus primitivas.
Me parece que en realidad deben ser
exactamente lo mismo
: tomar dos variables de la pila y comparar sus valores.
Lo que cambia no es el comportamiento de
==
, es lo que representan los valores que está comparando.
Si las cosas que está comparando son primitivas, entonces el valor en la Pila es el valor de la primitiva misma.
Si está comparando objetos, entonces el valor en la pila es el valor de la referencia (y, por lo tanto, la dirección del objeto en el montón).
¿He entendido mal algo, o
==
realmente se comporta igual en todas las situaciones?
Puntos de bonificación si puede señalarme documentación sobre cómo esto realmente funciona debajo de las cubiertas.
Como dicen otras respuestas / comentarios, en el nivel del lenguaje Java la semántica del operador
==
se
especifica
(en
JLS 15.21
) de una manera independiente de la implementación.
Hablando estrictamente, no puede inferir los detalles de implementación "bajo el capó" del texto JLS.
Todo lo que puede decir es que cualquier implementación conforme de
==
debe
comportarse
de cierta manera.
Asumiré que estamos hablando de JVM convencionales donde la representación real de la máquina de una referencia es una dirección de máquina. Es posible implementar referencias de otras maneras; por ejemplo, utilizando algún tipo de mecanismo de direccionamiento indirecto, como un PIDLAM .
En el nivel de bytecode, hay varias instrucciones de bytecode
diferentes
que implementan la lógica de
==
según el tipo (
int
,
long
o reference).
Sin embargo, la semántica de las comparaciones es similar.
Una vez que los bytecodes han sido verificados como de tipo seguro, los enteros y las direcciones
pueden
manejarse de la misma manera con el propósito de
==
comparación a nivel de hardware.
En el nivel de hardware (instrucción de máquina)
==
funciona igual para los tipos integrales primitivos y los valores no primitivos.
En ambos casos, se ejecutará una instrucción de máquina que compara dos "palabras" tomadas de un registro o de la memoria (montón o pila).
La semántica especificada por JLS de
==
para
float
y
double
es un poco diferente porque los
valores especiales
(infinitos y
valores que
no son un número) necesitan un tratamiento especial.
Por ejemplo: NaN == NaN es
false
.
Consulte también el estándar de coma flotante IEEE 754.
Hay diferentes códigos de bytes para esto, y a nivel de hardware las instrucciones utilizadas son diferentes a las utilizadas en los casos de enteros y de referencia. (El tratamiento de valores especiales generalmente se maneja en el hardware flotante).
La semántica especificada por JLS de
==
para
boolean
,
byte
,
short
y
char
es promover los valores a otro tipo (
int
,
long
,
float
o
double
) antes de compararlos.
La promoción también ocurre con otros casos si los operandos tienen tipos diferentes (sin caja).
Además, el desempaquetado ocurre si uno (¡pero no ambos!) De los operandos está encuadrado.
Si ambos operandos están encuadrados, entonces
==
es una comparación de referencia.
Resumiendo lo anterior ...
¿He entendido mal algo, o == realmente se comporta igual en todas las situaciones?
No, no lo hace, si incluye tipos de punto flotante y las consideraciones de ampliación primitiva y unboxing.
Puntos de bonificación si puede señalarme documentación sobre cómo esto realmente funciona debajo de las cubiertas.
No hay documentación pública oficial (Oracle) para esto. Las especificaciones JLS y JVM no prescriben estrategias de implementación.
Entiendo su explicación, y es correcto dadas ciertas definiciones de términos. Pero no se ajusta a la forma en que Java habla de objetos y primitivas.
La idea de una ''referencia'' a un objeto en Java se minimiza seriamente; Creo que es posible ser un ''programador de Java'' y no entender realmente qué es una referencia. Puede memorizar las reglas donde hace la diferencia (el operador ''=='', el paso de parámetros a los métodos) y no entender cómo se implementa o podría implementarse.
Así que creo que sería confuso para muchas personas que programan en Java decir que == ''se comporta igual en todas las situaciones'', porque eso implica demasiado conocimiento ''encubierto''. Java no lo alienta (ni le exige) que se vea ''en secreto'' hasta ese punto.