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

Analisi dettagliata dei problemi di confronto in Java

Il problema di confronto in Java è un problema di base e facile da confondere. Oggi, facciamo un'elaborazione dettagliata e ordinata di alcuni punti facili da sbagliare, sperando che sia utile per lo studio e l'intervista.

Primo, la differenza tra == e equals()

Prima di tutto, dobbiamo sapere la differenza tra == e equals(), == confronta sempre gli indirizzi, per i tipi di dati primari, il confronto == è in realtà se il valore della variabile è uguale, mentre per i tipi di dati referenziali, il confronto è l'indirizzo. Ecco un punto importante da notare, il tipo String è facile da usare ==, facile a sbagliare. Il metodo equals() è un metodo della classe Object, sappiamo che in Java ogni classe eredita per default la classe Object, quindi ogni oggetto ha un metodo equals(). Il metodo equals() della classe Object è come segue:

Dal codice sorgente possiamo vedere che il metodo equals() della classe Object utilizza anche == come base, quindi in realtà confronta anche i valori degli indirizzi. Pertanto, se si desidera utilizzare il metodo equals() per altri confronti, è necessario sovrascrivere il metodo equals().

Secondo, i tipi di dati primari e le loro classi wrapper

Sappiamo tutti che byte, short, int, long, boolean, char, double, float questi otto sono tipi di dati primari, e le variabili dichiarate da loro sono memorizzate nella memoria dello stack. Mentre i tipi di dati connessi (Byte, Short, Integer, Long, Boolean, Character, Double) definiti dalle loro classi wrapper esistono nella memoria heap. Per i tipi di dati primari, il loro confronto è relativamente semplice, ovvero se sono uguali usare ==, e per confrontare le dimensioni usare <, >, <=, >=. Per i tipi di dati wrapper, è un po' diverso.

Prima di tutto, guardiamo il risultato dell'esecuzione del seguente codice per determinare se sono uguali:

package dailytest;
import org.junit.Test;
/**
 * Sintesi delle comparazioni in Java
 * @author yrr
 */
public class JavaCompareTest {
  /**
   * Giudizio dell'uguaglianza del tipo Integer
   */
  @Test
  public void test01() {
    int n3 = 48;
    System.out.println("--------使用new对象时,当值在[-127,128]之间时---------");
    Integer n7 = new Integer(48);
    Integer n8 = new Integer(48);
    System.out.println(n7 == n8);  //false
    System.out.println(n7 == n3);  //true
    System.out.println("--------Metodo di assegnazione diretta, quando il valore è tra [-128, 127]---------");
    Integer n1 = 48;
    Integer n2 = 48;
    System.out.println(n3 == n1); //true
    System.out.println(n1 == n2); //true
    System.out.println(n1.equals(n2)); //true
    System.out.println(n1.equals(n3)); //true
    System.out.println(n1.intValue() == n2.intValue()); //true
    System.out.println("--------直接赋值方式,当值不在[-127,128]之间时---------");
    Integer n4 = 128;
    Integer n5 = 128;
    int n6 = 128;
    System.out.println(n4 == n5);  //false
    System.out.println(n4 == n6);  //true
    System.out.println(n4.equals(n5)); //true
    System.out.println(n4.equals(n6)); //true
    System.out.println(n4.intValue() == n5.intValue()); //true
    //Occorre verificare se Integer.intValue() è null quando lo si utilizza per prevenire l'eccezione NullPointException
  }
  /**
   * Verifica dell'uguaglianza del tipo Long
   */
  @Test
  public void test02() {
    //这里需要注意,使用long定义时,不需要加L或者l,而使用Long时必须加,否则会报错
    //建设都加上,以示区别
    long n3 = 48L;
    System.out.println("--------使用new对象时,当值在[-127,128]之间时---------");
    Long n7 = new Long(48);
    Long n8 = new Long(48);
    System.out.println(n7 == n8);  //false
    System.out.println(n7 == n3);  //true
    System.out.println("--------直接赋值方式,当值在[-127,128]之间时---------");
    Long n1 = 48L;
    Long n2 = 48L;
    System.out.println(n3 == n1); //true
    System.out.println(n1 == n2); //true
    System.out.println(n1.equals(n2)); //true
    System.out.println(n1.equals(n3)); //true
    System.out.println(n1.intValue() == n2.intValue()); //true
    System.out.println("--------直接赋值方式,当值不在[-127,128]之间时---------");
    Long n4 = 128L;
    Long n5 = 128L;
    long n6 = 128;
    System.out.println(n4 == n5);  //false
    System.out.println(n4 == n6);  //true
    System.out.println(n4.equals(n5)); //true
    System.out.println(n4.equals(n6)); //true
    System.out.println(n4.intValue() == n5.intValue()); //true
    //Quando si utilizza il metodo Long.intValue(), è necessario verificare se è null per prevenire l'eccezione NullPointException  
  }
}

Per quanto riguarda i risultati dell'esecuzione sopra, si fa la seguente spiegazione:

Prima di tutto, per dichiarare un oggetto Integer o Long con il metodo new, poiché i nuovi oggetti vengono creati in uno spazio di memoria sullo stack, quindi anche se i valori sono gli stessi, per ==, il confronto è il valore dell'indirizzo, quindi restituirà false. Per le classi di connessi ai tipi di dati fondamentali, è stato sovrascritto il metodo equals(), che compara le dimensioni dei numeri, quindi è possibile fare una judgments basati sulla dimensione del numero. Per il confronto tra variabili Integer e variabili int, si noterà che è basato sul confronto delle dimensioni dei numeri, perché nel confronto, il tipo Integer fa l'auto-boxing e si converte nel tipo int. Le spiegazioni dei primi tre punti si applicano a tutti i tipi di dati connessi Per il metodo di assegnazione diretta, quando il valore è 48, i due variabili Integer con == sono true, ma quando il valore è 128, diventa false. Questo perché in realtà, per Integer n1 = 48; questo metodo di assegnazione diretta chiama il metodo Integer.value(). Possiamo guardare semplicemente il codice sorgente del metodo Integer.value() come nell'immagine qui di seguito:

Possiamo vedere che qui c'è una condizione if, quando l'input di i è nell'intervallo [-128, 127], viene restituito direttamente dall'array IntegerCache. Quindi, per i numeri nell'intervallo, vengono restituiti i valori di indirizzo corrispondenti all'array, quindi il confronto con == restituirà true. Coloro che non sono nell'intervallo sono oggetti creati con new, quindi restituiranno false. Questa conclusione è valida per i tipi di dati Byte, Short, Integer, Long (chi è interessato può vedere il codice sorgente del loro metodo value()), perché l'intervallo di Byte è [-128, 127], quindi per il tipo Byte, l'uso di == e equals() non fa differenza. 

Per quanto riguarda la comparazione di grandezza, l'uso di >, <, <=, >= non presenta problemi, eseguiranno l'auto-boxing automatico. Tuttavia, solitamente si consiglia di utilizzare i seguenti due modi per la comparazione di grandezza:

Utilizzare il metodo xxxValue() per convertire in tipo di dati fondamentali e confrontarli. Utilizzare il metodo compareTo() per confrontare, nei tipi di dati connessi, è stato sovrascritto il metodo compareTo(). Consultare il codice sorgente di compareTo(), si può vedere che in realtà utilizza anche l'auto-boxing per convertire in tipo di dati fondamentali e confrontarli.

Secondo, la comparazione degli oggetti Java

Dopo la presentazione sopra, la comparazione degli oggetti diventa più facile. Il principio è lo stesso.

1. Confronto del tipo String

Occorre notare che il tipo String non può essere utilizzato direttamente con >, <=, >=, <, altrimenti si genererà un eccezione di compilazione.

package dailytest;
import org.junit.Test;
/**
 * Sintesi delle comparazioni in 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); //L'operatore < non è definito per il tipo di argomento java.lang.String, java.lang.String
    System.out.println(s1.compareTo(s3) < 0);  //true
  }
}

 2. Confronto degli oggetti di classe

La conclusione del confronto degli oggetti di classe è la stessa, ma è un po' più complessa rispetto ai tipi di dati primitivi e String.

Per determinare se due oggetti sono uguali secondo una certa regola, è necessario sovrascrivere il metodo equals() nella classe oggetto, come mostrato nel codice di esempio seguente:

package dailytest;
import org.junit.Test;
/**
 * Sintesi delle comparazioni in 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());
  }
}

E se si vuole confrontare la dimensione di due oggetti (questa è anche una domanda di intervista comune), ci sono due modi:

La classe da confrontare implementa l'interfaccia Comparable e ridefinisce il metodo compareTo(), o definisce una classe che implementa l'interfaccia Comparator e ridefinisce il metodo compare(). Le differenze tra i due sono che il primo viene definito sulla classe da confrontare, mentre il secondo viene definito al di fuori della classe. Questa differenza rende chiari i pro e i contro di entrambi: il primo è semplice, ma richiede di modificare la classe da confrontare, mentre il secondo non richiede modifiche al codice originale, offrendo maggiore flessibilità.

Primo metodo, ecco un esempio di codice:

package dailytest;
import org.junit.Test;
/**
 * Sintesi delle comparazioni in 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();
  }  
}

Secondo metodo, ecco un esempio di codice:

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("u1001", 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; 
  } 
}

Questo è tutto il contenuto relativo alla comparazione in Java che ti ho spiegato oggi, se hai altre domande, puoi discuterle nella sezione dei commenti qui sotto, grazie per il tuo supporto.

Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, il copyright è della proprietà del rispettivo autore, il contenuto è stato contribuito e caricato volontariamente dagli utenti di Internet, questo sito non detiene il diritto di proprietà, non è stato editato manualmente e non assume alcuna responsabilità legale. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.

Ti potrebbe interessare