relacionales - precedencia de operadores java
Cómo anular el método de igualdad en Java (9)
Punto 10: Obedece el contrato general cuando prevalece el igual
De acuerdo con Effective Java , Anular el método
equals
parece simple, pero hay muchas maneras de equivocarse, y las consecuencias pueden ser nefastas. La forma más fácil de evitar problemas no es anular el método deequals
, en cuyo caso cada instancia de la clase es igual a sí misma. Esto es lo correcto si se cumple alguna de las siguientes condiciones:
Cada instancia de la clase es inherentemente única . Esto es cierto para clases como Thread que representan entidades activas en lugar de valores. La implementación equals proporcionada por Object tiene exactamente el comportamiento correcto para estas clases.
No es necesario que la clase proporcione una prueba de "igualdad lógica". Por ejemplo, java.util.regex.Pattern podría haber reemplazado a igual para comprobar si dos instancias de patrón representaban exactamente la misma expresión regular, pero los diseñadores no pensaban que los clientes necesitarían o querrían esta funcionalidad. Bajo estas circunstancias, la implementación igual heredada de Object es ideal.
Una superclase ya ha anulado iguales, y el comportamiento de la superclase es apropiado para esta clase. Por ejemplo, la mayoría de las implementaciones de Set heredan su implementación equals de AbstractSet, las implementaciones de listas de AbstractList y las implementaciones de Map de AbstractMap.
La clase es privada o privada del paquete , y está seguro de que su método igual nunca se invocará. Si eres extremadamente reacio al riesgo, puedes anular el método equals para asegurarte de que no se invoca accidentalmente:
El método equals
implementa una relación de equivalencia. Tiene estas propiedades:
Reflexivo: Para cualquier valor de referencia no nulo
x
,x.equals(x)
debe devolver verdadero.Simétrico: Para cualquier valor de referencia no nulo
x
ey
,x.equals(y)
debe devolver verdadero si y solo si y.equals (x) devuelve verdadero.Transitivo: Para cualquier valor de referencia no nulo
x
,y
,z
, six.equals(y)
devuelvetrue
yy.equals(z)
devuelvetrue
, entoncesx.equals(z)
debe devolvertrue
.Constante: para cualquier valor de referencia no nulo
y
, las invocaciones múltiples dex.equals(y)
deben devolver de forma consistentetrue
o devolverse de manera consistentefalse
, siempre que no se modifique la información utilizada en comparaciones iguales.Para cualquier valor de referencia no nulo
x
,x.equals(null)
debe devolverfalse
.
Aquí hay una receta para un método de igual calidad de alta calidad:
Use el operador
==
para verificar si el argumento es una referencia a este objeto. Si es así, devuelve verdadero. Esta es solo una optimización del rendimiento, pero una que vale la pena si la comparación es potencialmente costosa.Use el operador
instanceof
para verificar si el argumento tiene el tipo correcto. Si no, devuelve falso. Normalmente, el tipo correcto es la clase en la que se produce el método. Ocasionalmente, es una interfaz implementada por esta clase. Use una interfaz si la clase implementa una interfaz que refine el contrato igual para permitir comparaciones entre las clases que implementan la interfaz. Las interfaces de colección como Set, List, Map y Map.Entry tienen esta propiedad.Echa el argumento al tipo correcto. Debido a que este elenco fue precedido por una instancia de prueba, se garantiza que tendrá éxito.
Para cada campo "significativo" en la clase, verifique si ese campo del argumento coincide con el campo correspondiente de este objeto. Si todas estas pruebas tienen éxito, devuelve verdadero; de lo contrario, devuelve falso. Si el tipo en el Paso 2 es una interfaz, debe acceder a los campos del argumento a través de métodos de interfaz; si el tipo es una clase, puede acceder a los campos directamente, dependiendo de su accesibilidad.
Para los campos primitivos cuyo tipo no es
float
odouble
, use el operador==
para las comparaciones; para los campos de referencia del objeto, llame al métodoequals
recursivamente; para los camposfloat
, use elFloat.compare(float, float)
estáticoFloat.compare(float, float)
; y para camposdouble
, useDouble.compare(double, double)
. El tratamiento especial de los campos flotantes y dobles se hace necesario por la existencia deFloat.NaN
,-0.0f
y los valores dobles análogos; Si bien puede compararfloat
y camposdouble
con los métodos estáticosFloat.equals
yDouble.equals
, esto implicaría el autoboxing en cada comparación, lo que tendría un rendimiento deficiente. Para los campos dearray
, aplique estas pautas a cada elemento. Si cada elemento en un campo de matriz es significativo, use uno de los métodosArrays.equals
.Algunos campos de referencia de objeto pueden contener legítimamente
null
. Para evitar la posibilidad de unaNullPointerException
, verifique esos campos para la igualdad utilizando el método estáticoObjects.equals(Object, Object)
.// Class with a typical equals method public final class PhoneNumber { private final short areaCode, prefix, lineNum; public PhoneNumber(int areaCode, int prefix, int lineNum) { this.areaCode = rangeCheck(areaCode, 999, "area code"); this.prefix = rangeCheck(prefix, 999, "prefix"); this.lineNum = rangeCheck(lineNum, 9999, "line num"); } private static short rangeCheck(int val, int max, String arg) { if (val < 0 || val > max) throw new IllegalArgumentException(arg + ": " + val); return (short) val; } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof PhoneNumber)) return false; PhoneNumber pn = (PhoneNumber)o; return pn.lineNum == lineNum && pn.prefix == prefix && pn.areaCode == areaCode; } ... // Remainder omitted }
Estoy intentando anular el método de igualdad en Java. Tengo una clase People que básicamente tiene 2 campos de datos nombre y edad. Ahora quiero anular el método de igual para poder verificar entre dos objetos de personas.
Mi código es el siguiente
public boolean equals(People other){
boolean result;
if((other == null) || (getClass() != other.getClass())){
result = false;
} // end if
else{
People otherPeople = (People)other;
result = name.equals(other.name) && age.equals(other.age);
} // end else
return result;
} // end equals
Pero cuando escribo age.equals (other.age) me da error ya que el método equals solo puede comparar String y age es Integer.
Por favor ayúdame a arreglar esto.
Gracias es Advance.
Utilicé el operador == como se sugirió y mi problema está resuelto. Muchas gracias a todos por hacer un esfuerzo para ayudarme.
Al comparar objetos en Java, realiza una comprobación semántica , comparando el tipo y el estado de identificación de los objetos a:
- sí mismo (misma instancia)
- sí mismo (clonar, o copia reconstruida)
- otros objetos de diferentes tipos
- otros objetos del mismo tipo
-
null
Reglas:
- Simetría :
a.equals(b) == b.equals(a)
-
equals()
siempre arrojatrue
ofalse
, pero nunca unaNullpointerException
,ClassCastException
o cualquier otra throwable
Comparación:
- Verificación de tipo : ambas instancias deben ser del mismo tipo, lo que significa que debe comparar las clases reales para la igualdad. Esto a menudo no se implementa correctamente, cuando los desarrolladores usan
instanceof
para la comparación de tipos (que solo funciona mientras no haya subclases, y viola la regla de simetría cuandoA extends B -> a instanceof b != b instanceof a)
. - Comprobación semántica del estado de identificación : asegúrese de comprender por qué estado se identifican las instancias. Las personas pueden ser identificadas por su número de seguro social, pero no por el color del pelo (puede teñirse), el nombre (puede cambiarse) o la edad (cambia todo el tiempo). Solo con objetos de valor debe comparar el estado completo (todos los campos no transitorios); de lo contrario, verifique solo lo que identifica a la instancia.
Para su clase de Person
:
public boolean equals(Object obj) {
// same instance
if (obj == this) {
return true;
}
// null
if (obj == null) {
return false;
}
// type
if (!getClass().equals(obj.getClass())) {
return false;
}
// cast and compare state
Person other = (Person) obj;
return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}
Clase de utilidad genérica reutilizable:
public final class Equals {
private Equals() {
// private constructor, no instances allowed
}
/**
* Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
*
* @param instance object instance (where the equals() is implemented)
* @param other other instance to compare to
* @param stateAccessors stateAccessors for state to compare, optional
* @param <T> instance type
* @return true when equals, false otherwise
*/
public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
if (instance == null) {
return other == null;
}
if (instance == other) {
return true;
}
if (other == null) {
return false;
}
if (!instance.getClass().equals(other.getClass())) {
return false;
}
if (stateAccessors == null) {
return true;
}
return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
}
}
Para su clase Person
, usando esta clase de utilidad:
public boolean equals(Object obj) {
return Equals.as(this, obj, t -> t.name, t -> t.age);
}
Como supongo que la age
es de tipo int
:
public boolean equals(Object other){
boolean result;
if((other == null) || (getClass() != other.getClass())){
result = false;
} // end if
else{
People otherPeople = (People)other;
result = name.equals(otherPeople.name) && age == otherPeople.age;
} // end else
return result;
} // end equals
El método equals define un parámetro de método de tipo Object y su tipo de retorno es booleano.
Don’t change the name of the method, its return type, or the type of method parameter
cuando defines ( anula ) este método en tu clase para comparar dos objetos.
public boolean equals(Object anObject) {
...
}
En primer lugar: no está anulando equals
, lo está sobrecargando .
Sin ver la declaración de age
real, es difícil decir por qué está recibiendo el error.
No estoy seguro de los detalles ya que no ha publicado todo el código, pero:
- recuerde anular
hashCode()
también - el método
equals
debería tenerObject
, noPeople
como su tipo de argumento. En este momento está sobrecargando, sin anular, el método equals, que probablemente no es lo que quiere, especialmente dado que revisa su tipo más tarde. - puede usar
instanceof
para verificar que se trata de un objeto People, por ejemploif (!(other instanceof People)) { result = false;}
-
equals
se usa para todos los objetos, pero no para primitivos. Creo que quieres decir que la edad es unint
(primitivo), en cuyo caso simplemente usa==
. Tenga en cuenta que un Entero (con una "I" mayúscula) es un Objeto que debe ser comparado con iguales.
Consulte ¿Qué problemas se deben tener en cuenta al anular equals y hashCode en Java? para más detalles.
si la edad es int, debe usar == si es un objeto Integer, entonces puede usar equals (). También debe implementar el método de código hash si anula los iguales. Los detalles del contrato están disponibles en el javadoc de Object y también en varias páginas en la web.
//Written by K@
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person("Subash Adhikari",28));
people.add(new Person("K",28));
people.add(new Person("",4));
people.add(new Person("Subash Adhikari",28));
for (int i=0;i<people.size()-1;i++){
for (int y=i+1;y<=people.size()-1;y++){
System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
boolean check = people.get(i).equals(people.get(y));
System.out.println(check);
}
}
}
}
//written by K@
public class Person {
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!Person.class.isAssignableFrom(obj.getClass())) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (this.age != other.age) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 53 * hash + this.age;
return hash;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Salida:
correr:
- Subash Adhikari - VS - K falso
- Subash Adhikari - VS - falso
- Subash Adhikari - VS - Subash Adhikari cierto
- K - VS - falso
- K - VS - Subash Adhikari falso
- - VS - Subash Adhikari falso
- CONSTRUIR ÉXITO (tiempo total: 0 segundos)
@Override
public boolean equals(Object that){
if(this == that) return true;//if both of them points the same address in memory
if(!(that instanceof People)) return false; // if "that" is not a People or a childclass
People thatPeople = (People)that; // than we can cast it to People safely
return this.name.equals(thatPeople.name) && this.age == thatPeople.age;// if they have the same name and same age, then the 2 objects are equal unless they''re pointing to different memory adresses
}