Elaborar sobre iguales y ==
1. Originado a partir de Objeto
Todos sabemos que todas las clases en Java heredan la superclase Object por defecto, y Object tiene más de 10 métodos, aquí presentamos los principales y toString
métodos .equals
hashcode
toSting
El método devuelve " " de forma predeterminada类名@地址值
; generalmente lo reescribimos y luego podemos imprimir directamente el objeto para obtener la forma reescrita de la salida.
Los siguientes puntos destacados equals
y hashcode
:
equals
El método compara el objeto (dirección) por defecto, es decir, se realiza la operación ==. Si el contenido necesita ser comparado, necesita ser reescrito.hashcode
El valor predeterminado es devolver una cadena de enteros basada en la dirección del objeto, lo que significa que la misma direcciónhashcode
es la misma. Yhashcode
es un método en Object, unnative
método local, lo que indica que el método se implementa llamando a otros lenguajes, que es un poco como una interfaz, y no necesita implementarlo usted mismo.
El siguiente es el código fuente relevante en la clase Object:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public boolean equals(Object obj) {
return (this == obj);
}
public native int hashCode();
2, enredado en cuerda
Hablemos de las características java.lang.String
de la neutralización :equals
hashcode
String equals
y hashcode
ambos se reescriben.
En primer lugar, el código hash calcula el hash de acuerdo con el contenido del objeto, por lo que el contenido del objeto es el mismo y su código hash es el mismo.
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
//这种 hash 计算方式不难看出,元素 value 相同 h 会是一样的
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
Para cadenas, equals compara el contenido del objeto, lo que también se debe a la especificidad de las cadenas.
Entonces == compara la dirección del objeto.
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;
}
3. Verificación de código
Aquí está el código de prueba:
public class TEST {
public static void main(String[] args){
Object o1 = new Object();
Object o2 = new Object();
Object o3 = o2;
System.out.println(o1==o2); //false
System.out.println(o1.equals(o2)); //false,Object 原生 equals,默认比较地址
System.out.println(o1.hashCode()==o2.hashCode()); //false,根据地址计算 hash
System.out.println(o2.hashCode()==o3.hashCode()); //true
String s1 = "abc";
String s2 = s1; //常量池优化机制
String s3 = new String("abc");
System.out.println(s1==s3); //false 地址不一样,一个在常量池中一个在堆中
System.out.println(s1.equals(s3)); //true,比较内容
System.out.println(s2.hashCode()==s1.hashCode()); //true,根据内容计算 hash
System.out.println(s1.hashCode()==s3.hashCode()); //true
}
}
4. Método de anulación
En algunos escenarios, necesitamos personalizar la regla "igual". Por ejemplo, si definimos el mismo contenido del objeto como igual, debemos anular el método de igualdad:
import java.util.Objects;
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object o) {
// 如果对象地址一样,则认为相同
if (this == o)
return true;
// 如果参数为空,或者类型信息不一样,则认为不同
if (o == null || getClass() != o.getClass())
return false;
// 转换为当前类型
Person person = (Person) o;
// 要求基本类型相等,并且将引用类型交给 java.util.Objects 类的 equals 静态方法取用结果
return age == person.age && Objects.equals(name, person.name);
}
}
//对象比较地址,字符串比较内容
public static boolean equals(Object a, Object b) {
//1,对象类型时
//a==b 为 true,则 true
//a==b 为 false,则 false;
//2,string 类型时
//地址 true,内容 true,则 true
//地址 false,内容 true,则 true;地址不等内容不等,flase
return (a == b) || (a != null && a.equals(b));
}
En algunas ocasiones, también necesitamos reescribir el código hash. Por ejemplo, el mecanismo de juicio de "igualdad de elementos" en HashSet es considerar exhaustivamente los métodos hashcode y equals, por lo que cuando personalizamos el objeto, debemos reescribir el código hash y equals. métodos.
La reescritura del método de equals se refiere al ejemplo anterior. La siguiente es la reescritura del método hashcode y el código fuente del método correspondiente:
@Override
public int hashCode() {
//仍然调用的是 Objects 的 hash 方法
//对于这里而言,age 走地址判断;name 走内容判断;所以只要他们内容相同就会返回相同的 hash
return Objects.hash(name, age);
}
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
//仍然走的是 Object 的 hashCode 方法
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
Por supuesto, el método de reescritura anterior, la generación de ideas, proporciona una plantilla de reescritura, que se puede generar con un solo clic.
5. Resumen
El código hash de Object devuelve el valor según la dirección, equals compara la dirección, == compara la dirección;
El código hash de String devuelve el valor según el contenido, equals compara el contenido, == compara la dirección.
Es decir, Object siempre compara la dirección. Debido a que String tiene un método de reescritura, es el contenido de la comparación. == es en realidad una dirección de comparación en sí misma.