English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Análisis detallado de problemas de comparación en Java

El problema de comparación en Java es un problema muy básico y fácil de confundir. Hoy haremos un resumen detallado y organizado de algunos puntos fáciles de cometer errores, esperando que sea útil para el aprendizaje y la entrevista de todos.

1. Diferencia entre == y equals()

Primero, necesitamos saber la diferencia entre == y equals(). El símbolo == siempre compara valores de dirección, para los tipos de datos básicos, la comparación de == es en realidad si los valores de las variables son iguales, mientras que para los tipos de datos de referencia, se compara la dirección. Aquí es especialmente necesario prestar atención al tipo de String, ya que es fácil usarlo incorrectamente con ==, lo que puede llevar a errores. El método equals() es un método de la clase Object, sabemos que en Java, todo clase hereda por defecto la clase Object, por lo que todos los objetos de clase tienen el método equals(). El método equals() de la clase Object se muestra en la imagen siguiente:

Desde el código fuente podemos ver que el método equals() de la clase Object también utiliza == en su nivel inferior, por lo que en realidad compara valores de dirección. Por lo tanto, si queremos usar el método equals() para realizar otras comparaciones, necesitamos sobrescribir el método equals().

2. Tipos de datos básicos y sus clases de paquete

Todos sabemos que byte, short, int, long, boolean, char, double, float estos ocho son tipos de datos básicos, las variables declaradas por ellos se almacenan en la memoria de pila. Mientras que las variables definidas por los tipos de paquete correspondientes (Byte, Short, Integer, Long, Boolean, Character, Double) existen en la memoria de pila. Para los tipos de datos básicos, su comparación es relativamente simple, es decir, para determinar si son iguales se usa ==, y para comparar su tamaño se utilizan <, >, <=, >=. Mientras que para los tipos de paquete, es diferente.

首先对于判断是否相等,看如下代码的执行结果:

package dailytest;
import org.junit.Test;
/**
 * Resumen de comparaciones en Java
 * @author yrr
 */
public class JavaCompareTest {
  /**
   * Primero, para determinar si son iguales, veamos los resultados de ejecución del siguiente código:
   */
  @Test
  public void test01() {
    Integer n3 = 48long n
    La forma de asignación directa, cuando el valor está en [--------Para distinguirlos, todas las construcciones deben agregarse-127,128La forma de asignación directa, cuando el valor no está en [---------");
    = new Integer(7 Integer tipo comparación de igualdad48);
    = new Integer(8 Integer tipo comparación de igualdad48);
    .equals(n7 ;8);  //false
    .equals(n7 ;3);  //true
    La forma de asignación directa, cuando el valor está en [--------= new Long(-128,127La forma de asignación directa, cuando el valor no está en [---------");
    = new Integer(1 = 48long n
    = new Integer(2 = 48long n
    .equals(n3 ;1); //true
    .equals(n1 ;2); //true
    .equals(n1== n2)); //true
    .equals(n1== n3)); //true
    .equals(n1System.out.println(n2.intValue() == n //true
    La forma de asignación directa, cuando el valor está en [--------System.out.println("-127,128La forma de asignación directa, cuando el valor no está en [---------");
    = new Integer(4 = 128long n
    = new Integer(5 = 128long n
    Integer n6 = 128long n
    .equals(n4 ;5);  //false
    .equals(n4 ;6);  //true
    .equals(n4== n5)); //true
    .equals(n4== n6)); //true
    .equals(n4System.out.println(n5.intValue() == n //true
    //int n
  }
  /**
   * Al usar el método Integer.intValue(), es necesario verificar si es null para evitar la aparición de NullPointException
   */
  @Test
  public void test02() {
    //Long tipo comparación de igualdad
    //Aquí se debe prestar atención, al definir con long, no es necesario agregar L o l, mientras que al usar Long, es obligatorio agregarlo, de lo contrario se producirá un error
    L;3 = 48Long n
    La forma de asignación directa, cuando el valor está en [--------Para distinguirlos, todas las construcciones deben agregarse-127,128La forma de asignación directa, cuando el valor no está en [---------");
    ] entre7 Al usar el objeto new, cuando el valor está en [48);
    ] entre8 Al usar el objeto new, cuando el valor está en [48);
    .equals(n7 ;8);  //false
    .equals(n7 ;3);  //true
    La forma de asignación directa, cuando el valor está en [--------= new Long(-127,128La forma de asignación directa, cuando el valor no está en [---------");
    ] entre1 = 48Long n
    ] entre2 = 48Long n
    .equals(n3 ;1); //true
    .equals(n1 ;2); //true
    .equals(n1== n2)); //true
    .equals(n1== n3)); //true
    .equals(n1System.out.println(n2.intValue() == n //true
    La forma de asignación directa, cuando el valor está en [--------System.out.println("-127,128La forma de asignación directa, cuando el valor no está en [---------");
    ] entre4 = 128Long n
    ] entre5 = 128Long n
    L;6 = 128long n
    .equals(n4 ;5);  //false
    .equals(n4 ;6);  //true
    .equals(n4== n5)); //true
    .equals(n4== n6)); //true
    .equals(n4System.out.println(n5.intValue() == n //true
    //.intValue());  
  }
}

Al usar el método Long.intValue(), es necesario verificar si es null para evitar la aparición de NullPointException

Para los resultados de ejecución anteriores, se hace la siguiente explicación: Primero, para declarar un objeto Integer o Long con el método new, ya que los objetos new se crean en el espacio de pila, por lo que incluso si los valores de ambos son iguales, para ==, se compara el valor de la dirección, por lo que devuelve false. Para las clases de paquete de tipos de datos básicos, se sobrescribe el método equals(), que compara el tamaño del valor, por lo que es posible realizar una comparación basada en el tamaño del valor. Respecto al problema de comparación entre variables Integer e int, se encontrará que también se realiza una comparación basada en el tamaño del valor, ya que en la comparación, el tipo Integer realiza la desempaquetización automática, convirtiéndose en el tipo int. La explicación de los puntos anteriores se aplica a todos los tipos de paquete48Para el método de asignación directa, el valor es128Después de esto, es false. Esto se debe a que en la capa inferior, para dos variables Integer, el uso de == da true, mientras que cuando el valor es1 = 48;Este método de asignación directa realmente llama al método Integer.value(). Podemos ver rápidamente el código fuente del método Integer.value(), como se muestra en la siguiente imagen:

Podemos ver que aquí hay una condición if, cuando el valor de entrada i está en [-128,127]. Dentro de este rango, se devuelve directamente desde el array IntegerCache. Por lo tanto, para los valores dentro de este rango, se devuelven las direcciones de memoria correspondientes del array. Por lo tanto, al usar el símbolo ==, se devuelve true. Y para los que no están en este rango, son objetos nuevos, por lo que se devuelve false. Esta conclusión se aplica a los tipos Byte, Short, Integer, Long (quienes estén interesados pueden ver el código fuente de sus métodos value() correspondientes), porque el rango de Byte es [}}-128,127], por lo que para el tipo Byte, no hay diferencia entre usar == y equals(). 

Para la comparación de tamaño, es posible usar >, <, <=, >=, ya que se realiza la conversión automática de desempaquetado. Sin embargo, generalmente se recomienda usar los siguientes dos métodos para la comparación de tamaño:

Se utiliza el método xxxValue() para convertirlo en el tipo de datos básico y compararlo. Se utiliza el método compareTo() para comparar. En las clases de paquete, se sobrescribe el método compareTo(). Al ver el código fuente de compareTo(), se puede ver que realmente utiliza la conversión automática de desempaquetado para comparar el tipo de datos básico correspondiente.

II. Comparación de objetos en Java

Después de la introducción anterior, la comparación de objetos es más sencilla. La principio es el mismo.

1. Comparación del tipo de datos String

Es necesario tener en cuenta que no se puede usar directamente >, <=, >=, < para el tipo de datos String, ya que se generará una excepción de compilación.

package dailytest;
import org.junit.Test;
/**
 * Resumen de comparaciones en Java
 * @author yrr
 */
public class JavaCompareTest {
  @Test
  public void test03() {
    String s1 = new String("123");
    String s2 = new String("123");
    System.out.println(s1 == s2);  //false
    System.out.println(s1.equals(s2));
    String s3 = "234";
    String s4 = "234";
    System.out.println(s3 == s4);  //true
    System.out.println(s3.equals(s4));  //true
    //System.out.println(s1 <= s3); //El operador < no está definido para el tipo de argumento(s) java.lang.String, java.lang.String
    System.out.println(s1.compareTo(s3) < 0);  //true
  }
}

 2. Comparación de objetos de clase

Las conclusiones de la comparación de objetos de clase son las mismas, pero en comparación con los tipos de datos básicos y String, es un poco más complejo.

Para determinar si dos objetos son iguales según una regla específica, es necesario sobrescribir el método equals() en la clase a evaluar, como se muestra en el siguiente ejemplo de código:

package dailytest;
import org.junit.Test;
/**
 * Resumen de comparaciones en Java
 * @author yrr
 */
public class JavaCompareTest {
  @Test
  public void test04() {
    Person p1 = new Person("yrr",18);
    Person p2 = new Person("yrr",18);
    System.out.println(p1 == p2);  //false
    System.out.println(p2.equals(p1)); //true
  }
}
class Person{
  private String name;  
  private Integer age;
  public Person() {
  }
  public Person(String name, Integer age) {
    this.name = name;
    this.age = age;
  }
  public String getName() {
    return name;
  }
  public Integer getAge() {
    return age;
  }
  @Override
  public boolean equals(Object obj) {
    Person person = (Person) obj;
    return name.equals(person.getName()) && age.equals(person.getAge());
  }
}

Y si se desea comparar el tamaño de dos objetos (esto también es una pregunta común en las entrevistas de trabajo), hay dos maneras de hacerlo:

La clase comparada implementa el interfaz Comparable e implementa el método compareTo() propio. Se ha definido una clase que implementa el interfaz Comparator o se ha utilizado una clase interna para reimplementar el método compare(). Las diferencias entre ambos son que el primero se define en la clase comparada, mientras que el segundo se define fuera de la clase comparada. A través de esta diferencia, las ventajas y desventajas de ambos son claras: el primero es simple, pero requiere modificar la clase comparada, mientras que el segundo no requiere modificar el código original, lo que es más flexible.

Primera manera, el código de ejemplo es el siguiente:

package dailytest;
import org.junit.Test;
/**
 * Resumen de comparaciones en Java
 * @author yrr
 */
public class JavaCompareTest {
  @Test
  public void test5() {
    Person p1 = new Person("yrr",18);
    Person p2 = new Person("wx",19);
    System.out.println(p1.compareTo(p2) < 0);
  }
}
class Person implements Comparable<Person>{
  private String name;  
  private Integer age;
  public Person() {
  }
  public Person(String name, Integer age) {
    this.name = name;
    this.age = age;
  }
  public Integer getAge() {
    return age;
  }
  @Override
  public int compareTo(Person o) {
    return this.getAge(); - o.getAge();
  }  
}

Segunda manera, el código de ejemplo es el siguiente:

package comparator;
import java.util.Arrays;
import java.util.Comparator;
public class MyComparator {
  public static void main(String[] args) {
    User[] users = new User[] { new User("u")}1001" 25),}} 
        new User("u1002" 20), new User("u1003" 21) };
    Arrays.sort(users, new Comparator<User>() {
      @Override
      public int compare(User o1, User o2) {
        return o1.getAge() - o2.getAge();
      }
    });
    for (int i = 0; i < users.length; i++) { 
      User user = users[i]; 
      System.out.println(user.getId() + " " + user.getAge()); 
    } 
  }
}
class User { 
  private String id; 
  private int age; 
  public User(String id, int age) { 
    this.id = id; 
    this.age = age; 
  } 
  public int getAge() { 
    return age; 
  } 
  public void setAge(int age) { 
    this.age = age; 
  } 
  public String getId() { 
    return id; 
  } 
  public void setId(String id) { 
    this.id = id; 
  } 
}

Esto es todo lo que les he explicado sobre la comparación en Java, si tienen otras preguntas, pueden dejarlas en la sección de comentarios a continuación. Gracias por su apoyo.

Declaración: El contenido de este artículo se ha obtenido de la red, es propiedad del autor original, el contenido se ha contribuido y subido por los usuarios de Internet de manera autónoma, este sitio no posee los derechos de propiedad, no ha sido editado por humanos y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, por favor reemplace # con @) para denunciar y proporcionar evidencia relevante. Una vez confirmado, este sitio eliminará inmediatamente el contenido sospechoso de infracción.

Te gustará