Comprenda la diferencia entre ==, equals y hashCode en java en diez minutos

Comencemos con un resumen:

  1. El operador == es juzgar si dos objetos son el mismo objeto, es decir, si sus direcciones son iguales
  2. es igual a y == en la clase de objeto son equivalentes
  3. Anular iguales se trata más de perseguir la igualdad lógica de dos objetos. Puede decir que el valor es igual o el contenido es igual. (Después de sobrescribir, siempre sobrescriba hashCode cuando sobrescriba igual)
  4. HashCode se usa para devolver el valor hash del objeto. Se usa principalmente para agilizar la búsqueda. Debido a que hashCode también está en el objeto Object, todos los objetos Java tienen un hashCode. En la estructura hash de HashTable y HashMap, ambos Find la posición en la tabla hash por hashCode.

1. Diferencia del operador Java ==

Los tipos de datos en Java se pueden dividir en dos categorías:

1. Tipos de datos básicos , también conocidos como tipos de datos primitivos

Para comparar byte, short, char, int, long, float, double, boolean, use el doble signo igual (==) y compare sus valores .

2. Tipo de referencia (clase, interfaz, matriz)

Cuando usan (==) para comparar, comparan sus direcciones de almacenamiento en la memoria , por lo tanto, a menos que sea el mismo objeto nuevo, el resultado de su comparación es verdadero, de lo contrario el resultado de la comparación es falso.

Los objetos se colocan en el montón y la referencia (dirección) del objeto se almacena en la pila . Se puede ver que '==' compara los valores en la pila. Si desea comparar si el contenido de los objetos en el montón es el mismo, debe anular el método equals .

2. Hay un operador == en Java, ¿por qué necesita iguales?

El papel de equals () es determinar si dos objetos son iguales. La definición en Object es:

//equals与==是等效的
public boolean equals(Object obj) {
        return (this == obj);
    }

Esto muestra que antes de implementar nuestro propio método equals, equals es equivalente a ==, y el operador == juzga si dos objetos son el mismo objeto, es decir, si sus direcciones son iguales. Anular iguales se trata más de perseguir la igualdad lógica de dos objetos. Puede decir que el valor es igual o el contenido es igual.
Reescritura del método equals en String.java

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

Aquí hay cinco puntos a tener en cuenta sobre los iguales nuevamente:

  1. Reflexividad: para cualquier valor de referencia X, el valor de retorno de x.equals (x) debe ser verdadero.
  2. Simetría: Para cualquier valor de referencia x, y, si y solo si el valor de retorno de y.equals (x) es verdadero, el valor de retorno de x.equals (y) debe ser verdadero;
  3. Transitividad: si x.equals (y) = verdadero, y.equals (z) = verdadero, entonces x.equals (z) = verdadero
  4. Coherencia: si no hay ningún cambio en el objeto de comparación, el resultado de la comparación no debería cambiar.
  5. No nulabilidad: para cualquier valor de referencia no nulo X, el valor de retorno de x.equals (nulo) debe ser falso

En las siguientes condiciones, el objetivo se puede lograr sin sobrescribir iguales:

  • Cada instancia de la clase es esencialmente única: aquellas que enfatizan la entidad activa y no se preocupan por el valor, como Thread, qué hilo nos importa, se pueden comparar con iguales en este momento.
  • No me importa si la clase proporciona una función de prueba de igualdad lógica: los usuarios de algunas clases no usarán su función de comparación, como la clase Random. Básicamente, nadie comparará dos valores aleatorios.
  • La superclase ya ha anulado equals, y la subclase solo necesita usar el comportamiento de la superclase: por ejemplo, si se ha sobrescrito igual en AbstractMap, entonces esta función también es necesaria en el comportamiento de la subclase heredada, y no necesita A ser implementado.
  • Si la clase es privada o privada a nivel de paquete, el método equals no es necesario: en este momento, debe anular el método equals para deshabilitarlo:
@Override public boolean equals(Object obj) { throw new AssertionError();}

3. ¿Cuál es el uso de hashCode?

El método hashCode () devuelve un valor, como se puede ver en el nombre del método, su propósito es generar un código hash. El propósito principal del código hash es ingresar como clave cuando se aplica el hash a un objeto, a partir de esto, es fácil inferir que necesitamos que el código hash de cada objeto sea lo más diferente posible para garantizar el rendimiento de acceso del hash. De hecho, la implementación predeterminada proporcionada por la clase Object garantiza que el código hash de cada objeto sea diferente (se devuelve un código hash a través de un algoritmo específico basado en la dirección de memoria del objeto). Java utiliza el principio de tablas hash. Hash es en realidad un nombre personal. Debido a que propuso un concepto de algoritmo hash, fue nombrado en su honor. El algoritmo hash también se denomina algoritmo hash, que asigna directamente datos a una dirección de acuerdo con un algoritmo específico . Los principiantes pueden entender que el método hashCode en realidad devuelve la dirección física del almacenamiento del objeto (puede que no lo sea).

3.1 El papel de hashCode

Para comprenderlo, primero debe conocer las colecciones en Java.  
En general, hay dos tipos de colecciones en Java, una es List y la otra es Set. Los elementos del primer conjunto están ordenados y los elementos pueden repetirse; los elementos del segundo están desordenados, pero los elementos no pueden repetirse.

Luego hay un problema más serio: si desea asegurarse de que los elementos no se repitan, ¿cuál debería ser la base para juzgar si dos elementos se repiten?

Este es el método Object.equals. Sin embargo, si la verificación se realiza cada vez que se agrega un elemento, cuando hay muchos elementos, el número de comparaciones de los elementos agregados al conjunto será muy grande. En otras palabras, si ya hay 1000 elementos en la colección, cuando el elemento número 1001 se agregue a la colección, llamará al método equals 1000 veces. Obviamente, esto reducirá en gran medida la eficiencia.
Por lo tanto, Java utiliza el principio de tablas hash.

De esta forma, cuando se agrega un nuevo elemento a la colección,

Llame primero al método hashCode de este elemento y podrá ubicar la ubicación física donde debe colocarse de inmediato.

Si no hay ningún elemento en esta posición, se puede almacenar directamente en esta posición sin ninguna comparación;

Si ya hay un elemento en esta posición, llama a su método equals para compararlo con el nuevo elemento. Si es el mismo, no se almacenará. Si no lo está, hará un hash de otras direcciones. Entonces aquí hay un problema de resolución de conflictos. De esta manera, el número de llamadas reales al método equals se reduce en gran medida, casi solo una o dos veces.

 

Diagrama de expansión del conocimiento (resumido y ampliado de la siguiente manera):

 

Supongo que te gusta

Origin blog.csdn.net/qq_27828675/article/details/102551384
Recomendado
Clasificación