Porovnávanie objektov v Jave

1. Úvod

Porovnávanie objektov je podstatnou vlastnosťou objektovo orientovaných programovacích jazykov.

V tomto výučbe sa pozrieme na niektoré z funkcií jazyka Java, ktoré nám umožňujú porovnávať objekty. Ďalej sa pozrieme na tieto funkcie v externých knižniciach.

2. == a != Operátorov

Začnime s == a != operátory, ktoré dokážu zistiť, či sú dva objekty Java rovnaké alebo nie.

2.1. Primitív

Pre primitívne typy to isté znamená, že majú rovnaké hodnoty:

assertThat (1 == 1) .isTrue ();

Vďaka automatickému rozbaleniu toto funguje aj pri porovnaní primitívnej hodnoty s jej náprotivkom typu wrapper:

Celé číslo a = nové celé číslo (1); assertThat (1 == a) .isTrue ();

Ak majú dve celé čísla rôzne hodnoty, znak == operátor by sa vrátil nepravdivé, kým != operátor by sa vrátil pravda.

2.2. Predmety

Povedzme, že chceme porovnať dve Celé číslo typy obalov s rovnakou hodnotou:

Celé číslo a = nové celé číslo (1); Celé číslo b = nové celé číslo (1); assertThat (a == b) .isFalse ();

Porovnaním dvoch objektov hodnota týchto objektov nie je 1. Ide skôr o ich pamäťové adresy v zásobníku ktoré sa líšia, pretože obidva objekty boli vytvorené pomocou Nový operátor. Keby sme mali pridelené a do b, potom by sme mali iný výsledok:

Celé číslo a = nové celé číslo (1); Celé číslo b = a; assertThat (a == b) .isTrue ();

Teraz sa pozrime, čo sa stane, keď použijeme Celé číslo # hodnotaOf továrenská metóda:

Celé číslo a = Integer.valueOf (1); Celé číslo b = Integer.valueOf (1); assertThat (a == b) .isTrue ();

V takom prípade sa považujú za rovnaké. Je to preto, lebo hodnota() metóda ukladá Celé číslo v pamäti cache, aby sa zabránilo vytváraniu príliš veľa obalových objektov s rovnakou hodnotou. Preto metóda vracia to isté Celé číslo napríklad pre oba hovory.

Java to tiež robí pre String:

assertThat ("Dobrý deň!" == "Dobrý deň!"). isTrue ();

Ak však boli vytvorené pomocou Nový operátor, potom by neboli rovnaké.

Nakoniec dva nulový odkazy sa považujú za rovnaké, zatiaľ čo akékoľveknulový objekt bude považovaný za odlišný od nulový:

assertThat (null == null) .isTrue (); assertThat ("Dobrý deň!" == null) .isFalse ();

Správanie operátorov rovnosti môže byť samozrejme limitujúce. Čo ak chceme porovnať dva objekty namapované na rôzne adresy a napriek tomu ich považovať za rovnocenné na základe ich vnútorných stavov? Uvidíme, ako na to v ďalších častiach.

3. Objekt # sa rovná Metóda

Poďme si teraz povedať o širšej koncepcii rovnosti s rovná sa () metóda.

Táto metóda je definovaná v dokumente Objekt triedy tak, aby ho dedil každý objekt Java. Predvolene, jeho implementácia porovnáva adresy pamäte objektov, takže funguje rovnako ako == operátor. Túto metódu však môžeme prepísať, aby sme definovali, čo znamená rovnosť pre naše objekty.

Najprv sa pozrime, ako sa chová k existujúcim objektom ako Celé číslo:

Celé číslo a = nové celé číslo (1); Celé číslo b = nové celé číslo (1); assertThat (a.equals (b)). isTrue ();

Metóda sa stále vracia pravda keď sú oba objekty rovnaké.

Mali by sme poznamenať, že môžeme zložiť a nulový objekt ako argument metódy, ale samozrejme, nie ako objekt, na ktorý metódu nazývame.

Môžeme použiť rovná sa () metóda s vlastným predmetom. Povedzme, že máme Osoba trieda:

verejná trieda Osoba {private String firstName; private String priezvisko; public Person (String firstName, String lastName) {this.firstName = firstName; this.lastName = priezvisko; }}

Môžeme prepísať rovná sa () metóda pre túto triedu, aby sme mohli porovnať dve Osobas na základe ich interných podrobností:

@ Override public boolean equals (Object o) if (this == o) return true; if (o == null 

Ďalšie informácie nájdete v našom článku venovanom tejto téme.

4. Objekty # sa rovnajú Statická metóda

Poďme sa teraz pozrieť na Objekty # sa rovnajú statická metóda. Už sme spomínali, že to nemôžeme použiť nulový ako hodnota prvého objektu inak a NullPointerException by bol vyhodený.

The rovná sa () metóda Predmety pomocná trieda tieto problémy rieši. Vyžaduje si to dva argumenty a porovná ich, a to aj so zvládnutím nulový hodnoty.

Poďme to porovnať Osoba objekty znova s:

Osoba joe = nová osoba ("Joe", "Portman"); Osoba joeAgain = nová osoba ("Joe", "Portman"); Osoba natalie = nová osoba ("Natalie", "Portman"); assertThat (Objects.equals (joe, joeAgain)). isTrue (); assertThat (Objects.equals (joe, natalie)). isFalse ();

Ako sme už povedali, metóda sa zvláda nulový hodnoty. Preto, ak sú obidva argumenty nulový vráti sa to pravda, a ak je len jeden z nich nulový, vráti sa nepravdivé.

To môže byť naozaj užitočné. Povedzme, že k nášmu chceme pridať voliteľný dátum narodenia Osoba trieda:

public Person (String meno, String priezvisko, LocalDate dátum narodenia) {this (meno, priezvisko); this.birthDate = dátum narodenia; }

Potom by sme museli aktualizovať naše rovná sa () metóda ale s nulový manipulácia. Mohli by sme to urobiť pridaním tejto podmienky k našej rovná sa () metóda:

dátum narodenia == null? that.birthDate == null: birthDate.equals (that.birthDate);

Ak však do svojej triedy pridáme veľa polí s povolenou hodnotou Null, môže to byť naozaj nepríjemné. Pomocou Objekty # sa rovnajú metóda v našom rovná sa () implementácia je oveľa čistejšia a zlepšuje čitateľnosť:

Objects.equals (dátum narodenia, ten dátum narodenia);

5. Porovnateľné Rozhranie

Porovnávaciu logiku možno použiť aj na umiestnenie objektov v konkrétnom poradí. The Porovnateľné rozhranie nám umožňuje definovať usporiadanie medzi objektmi, určením, či je objekt väčší, rovný alebo menší ako iný.

The Porovnateľné rozhranie je všeobecné a má iba jednu metódu, porovnať s(), ktorý vezme argument generického typu a vráti znak int. Vrátená hodnota je záporná, ak toto je nižšie ako argument, 0, ak sú rovnaké, a inak pozitívne.

Povedzme, v našom Osoba triedy, chceme porovnávať Osoba objekty podľa ich priezviska:

public class Person implements Comparable {// ... @Override public int compareTo (Person o) {return this.lastName.compareTo (o.lastName); }}

The porovnať s() metóda vráti zápor int ak sa volá s Osoba ktoré majú väčšie priezvisko ako toto, nula, ak je rovnaké priezvisko, a inak kladné.

Viac informácií nájdete v našom článku venovanom tejto téme.

6. Komparátor Rozhranie

The Komparátor rozhranie je všeobecné a má porovnaj metóda, ktorá vezme dva argumenty tohto generického typu a vráti znak celé číslo. Tento vzor sme už videli skôr s Porovnateľné rozhranie.

Komparátor je podobný; je to však oddelené od definície triedy. Preto môžeme ich definovať toľko Komparátory chceme triedu, kde môžeme poskytnúť iba jednu Porovnateľné implementácia.

Poďme si predstaviť, že máme webovú stránku, ktorá zobrazuje ľudí v tabuľkovom zobrazení, a chceme používateľovi ponúknuť možnosť zoradiť ich podľa krstného mena a nie podľa priezviska. Nie je to možné Porovnateľné ak si tiež chceme ponechať našu súčasnú implementáciu, ale mohli by sme implementovať našu vlastnú Komparátory.

Vytvorme a OsobaKomparátor ktorý ich porovná iba podľa krstného mena:

Comparator compareByFirstNames = Comparator.comparing (Osoba :: getFirstName);

Poďme teraz triediť a Zoznam ľudí, ktorí to používajú Komparátor:

Osoba joe = nová osoba ("Joe", "Portman"); Osoba allan = nová osoba ("Allan", "Dale"); Zoznam ľudí = nový ArrayList (); people.add (joe); people.add (allan); people.sort (compareByFirstNames); tvrdiťTo (ľudia) .obsahuje Presne (allan, joe);

Existujú ďalšie metódy Komparátor rozhranie, ktoré môžeme použiť v našom porovnať s() implementácia:

@Override public int compareTo (Person o) {return Comparator.comparing (Person :: getLastName) .thComComing (Person :: getFirstName) .thComComing (Person :: getBirthDate, Comparator.nullsLast (Comparator.naturalOrder ())) .compare ( toto, o); }

V tomto prípade najskôr porovnávame priezviská, potom mená. Potom porovnáme dátumy narodenia, ale keďže majú povolenú hodnotu Null, musíme povedať, ako s tým zaobchádzať, a tak dáme druhý argument, ktorý hovorí, že by sa mali porovnávať podľa ich prirodzeného poradia, ale s nulový hodnoty idú posledné.

7. Apache Commons

Poďme sa teraz pozrieť na knižnicu Apache Commons. Najskôr importujme závislosť Maven:

 org.apache.commons commons-lang3 3.10 

7.1. ObjectUtils # notEqual Metóda

Najprv si povieme niečo o ObjectUtils # notEqual metóda. Treba na to dvoch Objekt argumenty, podľa ktorých určia, či nie sú rovnaké rovná sa () implementácia metódy. Aj to zvláda nulový hodnoty.

Znovu použijeme naše String príklady:

Reťazec a = nový Reťazec („Ahoj!“); Reťazec b = nový Reťazec („Hello World!“); assertThat (ObjectUtils.notEqual (a, b)). isTrue (); 

Je potrebné poznamenať, že ObjectUtilsrovná sa () metóda. To je však zastarané od Javy 7, kedy Objekty # sa rovnajú objavil sa

7.2. ObjectUtils # porovnaj Metóda

Teraz porovnajme poradie objektov s ObjectUtils # porovnaj metóda. Je to všeobecná metóda, ktorá vyžaduje dva Porovnateľné argumenty tohto generického typu a vráti Celé číslo.

Uvidíme, že pomocou Struny ešte raz:

Prvý reťazec = nový reťazec („Ahoj!“); Druhý reťazec = nový reťazec ("Ako sa máš?"); assertThat (ObjectUtils.compare (prvý, druhý)). isNegative ();

Metóda je predvolene spracovaná nulový ich hodnotami ako väčšími. Ponúka preťaženú verziu, ktorá ponúka zvrátenie tohto správania a jeho zníženie, pričom boolovský argument.

8. Guava

Poďme sa teraz pozrieť na Guava. Najskôr importujme závislosť:

 com.google.guava guava 29.0-jre 

8.1. Objekty # rovnaké Metóda

Podobne ako v knižnici Apache Commons, aj Google nám poskytuje metódu na zisťovanie, či sú dva objekty rovnaké, Objekty # rovnaké. Aj keď majú rôzne implementácie, vracajú rovnaké výsledky:

Reťazec a = nový Reťazec („Ahoj!“); Reťazec b = nový Reťazec („Ahoj!“); assertThat (Objects.equal (a, b)). isTrue ();

Aj keď to nie je označené ako zastarané, JavaDoc tejto metódy hovorí, že by sa malo považovať za zastarané, pretože Java 7 poskytuje Objekty # sa rovnajú metóda.

8.2. Porovnávacie metódy

Knižnica Guava teraz neponúka metódu na porovnanie dvoch objektov (v nasledujúcej časti uvidíme, čo môžeme urobiť, aby sme to dosiahli), ale poskytuje nám metódy na porovnanie primitívnych hodnôt. Zoberme si Ints pomocná trieda a uvidíte, ako na tom porovnať () metóda funguje:

assertThat (Ints.compare (1, 2)). isNegative ();

Ako obvykle vracia celé číslo to môže byť záporné, nulové alebo kladné, ak je prvý argument menší, rovnaký alebo väčší ako druhý argument. Podobné metódy existujú pre všetky primitívne typy, s výnimkou bajtov.

8.3. PorovnanieRetazec Trieda

Napokon knižnica Guava ponúka PorovnanieRetazec trieda, ktorá nám umožňuje porovnávať dva objekty prostredníctvom reťazca porovnaní. Ľahko môžeme porovnať dve Osoba objekty podľa mena a priezviska:

Osoba natalie = nová osoba ("Natalie", "Portman"); Osoba joe = nová osoba ("Joe", "Portman"); int comparisonResult = ComparisonChain.start () .compare (natalie.getLastName (), joe.getLastName ()) .compare (natalie.getFirstName (), joe.getFirstName ()) .result (); assertThat (comparisonResult) .isPositive ();

Základné porovnanie sa dosiahne pomocou porovnať s() metóda, takže argumenty prešli na porovnať () metódy musia byť primitívne alebo Porovnateľnés.

9. Záver

V tomto článku sme sa zaoberali rôznymi spôsobmi porovnania objektov v Jave. Skúmali sme rozdiel medzi rovnakosťou, rovnosťou a usporiadaním. Pozreli sme sa tiež na zodpovedajúce funkcie v knižniciach Apache Commons a Guava.

Celý kód tohto článku nájdete ako obvykle na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found