Chciałem wyjaśnić, czy dobrze to rozumiem:
==
jest porównaniem odniesienia, tzn. oba obiekty wskazują to samo miejsce w pamięci.equals()
ocenia do porównania wartości w obiektach
.equals()
jak sensownie odpowiednik
Chciałem wyjaśnić, czy dobrze to rozumiem:
==
jest porównaniem odniesienia, tzn. oba obiekty wskazują to samo miejsce w pamięci.equals()
ocenia do porównania wartości w obiektach.equals()
jak sensownie odpowiednik
Odpowiedzi:
Zasadniczo odpowiedź na twoje pytanie brzmi „tak”, ale ...
.equals(...)
porówna tylko to, co napisano do porównania, nie więcej, nie mniej.equals(Object o)
metoda najbliższej klasy nadrzędnej, która zastąpiła tę metodę.Object#equals(Object o)
metoda. Dla interfejsu API obiektu jest to to samo, co ==
; to znaczy zwraca prawdę wtedy i tylko wtedy, gdy obie zmienne odnoszą się do tego samego obiektu, jeśli ich odwołania są takie same. W ten sposób będziesz testować równość obiektów, a nie równość funkcjonalną .hashCode
jeśli nadpisujesz, equals
aby nie „zerwać kontraktu”. Zgodnie z interfejsem API wynik zwracany z hashCode()
metody dla dwóch obiektów musi być taki sam, jeśli ich equals
metody wykazują, że są one równoważne. Odwrotna sytuacja nie musi być prawdą.==
sprawdza referencje pamięci, to dlaczego otrzymuję to dziwne zachowanie w [this] [1] [1]: docs.google.com/document/d/… Spodziewałem się, że dane wyjściowe będą prawdziwe. mogę usunąć moje nieporozumienia
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
<br/> Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
( docs.oracle.com/javase/7/docs/api/java/lang/… )
W odniesieniu do klasy String:
Równości () Sposób porównuje „wartość” wewnątrz przypadkach łańcuch znaków (na hałdy), niezależnie, czy dwa odniesienia obiektów odnoszą się do tego samego przykładu łańcuchach lub nie. Jeśli jakieś dwa odwołania do obiektów typu String odnoszą się do tej samej instancji String, to świetnie! Jeśli dwa odwołania do obiektów odnoszą się do dwóch różnych instancji String ... nie robi to różnicy. Jest to „wartość” (to znaczy zawartość tablicy znaków) w każdej porównywanej instancji String.
Z drugiej strony operator „==” porównuje wartość dwóch odwołań do obiektów, aby sprawdzić, czy odnoszą się one do tej samej instancji String . Jeśli wartość obu odwołań do obiektów „odnosi się” do tej samej instancji String, wynikiem wyrażenia logicznego byłoby „true” .. duh. Jeśli natomiast wartość obu odwołań do obiektów „odnosi się” do różnych instancji String (mimo że obie instancje String mają identyczne „wartości”, to znaczy zawartość tablic znaków każdej instancji String jest taka sama), wynikiem wyrażenia logicznego byłoby „fałsz”.
Jak w przypadku każdego wyjaśnienia, pozwól mu się zanurzyć.
Mam nadzieję, że to trochę wyjaśni.
String
s, ==
odniesienie jest również równe, tak, ale zwykle działa (jak w dwóch String
sekundach z tą samą zawartością zwykle będą ==
do siebie), z powodu tego, jak Java obsługuje String
s. Nie zawsze będzie to z pewnością zła praktyka, ale jest to powszechny błąd, szczególnie wśród osób pochodzących z innych języków.
String
build z literału łańcuchowego zostanie dodany do czegoś zwanego String constant pool
np. String s1 = "someString"; String s2 = "someString;"
oba s1
i s2
będą dzielić to samo odwołanie. s1 == s2
zwróci prawdę. Ale jeśli zostały zbudowane String constructor
np. String s1 = new String("someString"); String s2 = new String("someString");
, To nie będą dzielić tego samego odniesienia. s1 == s2
zwróci fałsz.
Istnieją niewielkie różnice w zależności od tego, czy mówimy o „prymitywach”, czy „typach obiektów”; to samo można powiedzieć, jeśli mówimy o członkach „statycznych” lub „niestatycznych”; możesz także wymieszać wszystkie powyższe ...
Oto przykład (możesz go uruchomić):
public final class MyEqualityTest
{
public static void main( String args[] )
{
String s1 = new String( "Test" );
String s2 = new String( "Test" );
System.out.println( "\n1 - PRIMITIVES ");
System.out.println( s1 == s2 ); // false
System.out.println( s1.equals( s2 )); // true
A a1 = new A();
A a2 = new A();
System.out.println( "\n2 - OBJECT TYPES / STATIC VARIABLE" );
System.out.println( a1 == a2 ); // false
System.out.println( a1.s == a2.s ); // true
System.out.println( a1.s.equals( a2.s ) ); // true
B b1 = new B();
B b2 = new B();
System.out.println( "\n3 - OBJECT TYPES / NON-STATIC VARIABLE" );
System.out.println( b1 == b2 ); // false
System.out.println( b1.getS() == b2.getS() ); // false
System.out.println( b1.getS().equals( b2.getS() ) ); // true
}
}
final class A
{
// static
public static String s;
A()
{
this.s = new String( "aTest" );
}
}
final class B
{
private String s;
B()
{
this.s = new String( "aTest" );
}
public String getS()
{
return s;
}
}
Możesz porównać objaśnienia dla „==” (operator równości) i „.equals (...)” (metoda w klasie java.lang.Object) za pomocą tych łączy:
Różnica między == i równa mi się przez jakiś czas myliła, dopóki nie zdecydowałem się przyjrzeć jej bliżej. Wielu z nich twierdzi, że do porównywania ciągów powinieneś używać, equals
a nie używać==
. Mam nadzieję, że w tej odpowiedzi będę mógł powiedzieć różnicę.
Najlepszym sposobem na udzielenie odpowiedzi na to pytanie będzie zadanie sobie kilku pytań. a więc zacznijmy:
Jakie są dane wyjściowe dla poniższego programu:
String mango = "mango";
String mango2 = "mango";
System.out.println(mango != mango2);
System.out.println(mango == mango2);
Jeśli powiesz,
false
true
Powiem, że masz rację, ale dlaczego to powiedziałeś ? a jeśli powiesz, że wynik jest
true
false
Powiem, że się mylisz, ale wciąż będę cię pytać, dlaczego uważasz, że tak jest?
Ok, spróbujmy odpowiedzieć na to:
Jakie są dane wyjściowe dla poniższego programu:
String mango = "mango";
String mango3 = new String("mango");
System.out.println(mango != mango3);
System.out.println(mango == mango3);
Teraz, jeśli powiesz,
false
true
Powiem, że się mylisz, ale dlaczego teraz się mylisz ? poprawne wyjście dla tego programu to
true
false
Porównaj powyższy program i spróbuj o tym pomyśleć.
Ok. Teraz to może pomóc (przeczytaj to: wydrukuj adres obiektu - nie jest to możliwe, ale nadal możemy go używać).
String mango = "mango";
String mango2 = "mango";
String mango3 = new String("mango");
System.out.println(mango != mango2);
System.out.println(mango == mango2);
System.out.println(mango3 != mango2);
System.out.println(mango3 == mango2);
// mango2 = "mang";
System.out.println(mango+" "+ mango2);
System.out.println(mango != mango2);
System.out.println(mango == mango2);
System.out.println(System.identityHashCode(mango));
System.out.println(System.identityHashCode(mango2));
System.out.println(System.identityHashCode(mango3));
czy możesz po prostu pomyśleć o wynikach trzech ostatnich wierszy powyższego kodu: dla mnie ideone wydrukował to ( możesz sprawdzić kod tutaj ):
false
true
true
false
mango mango
false
true
17225372
17225372
5433634
O! Teraz widzisz tożsamośćHashCode (mango) jest równa identycznościHashCode (mango2) Ale nie jest równa identycznościHashCode (mango3)
Mimo że wszystkie zmienne łańcuchowe - mango, mango2 i mango3 - mają tę samą wartość, czyli „mango”,identityHashCode()
nadal nie jest taka sama dla wszystkich.
Teraz spróbuj odkomentować tę linię // mango2 = "mang";
i uruchom ją ponownie, tym razem zobaczysz wszystkie trzyidentityHashCode()
są różne. Hmm, to jest przydatna wskazówka
wiemy, że jeśli hashcode(x)=N
ihashcode(y)=N
=>x is equal to y
Nie jestem pewien, jak java działa wewnętrznie, ale zakładam, że tak się stało, kiedy powiedziałem:
mango = "mango";
java utworzyła ciąg, "mango"
który został wskazany (przywołany) przez zmienną mango
coś takiego
mango ----> "mango"
Teraz w następnym wierszu, kiedy powiedziałem:
mango2 = "mango";
W rzeczywistości użył ponownie tego samego ciągu, "mango"
który wygląda mniej więcej tak
mango ----> "mango" <---- mango2
Zarówno mango, jak i mango2 wskazują na to samo odniesienie Teraz, kiedy powiedziałem
mango3 = new String("mango")
W rzeczywistości stworzył zupełnie nowe odniesienie (ciąg znaków) dla „mango”. który wygląda mniej więcej tak
mango -----> "mango" <------ mango2
mango3 ------> "mango"
i dlatego, gdy podałem wartości dla mango == mango2
, to zgasło true
. a kiedy wyłożyłem wartość mango3 == mango2
, zgasłofalse
(nawet gdy wartości są takie same).
a kiedy odkomentowałeś linię, // mango2 = "mang";
faktycznie utworzył ciąg „mang”, który zmienił nasz wykres w ten sposób:
mango ---->"mango"
mango2 ----> "mang"
mango3 -----> "mango"
To dlatego identyfikator tożsamości nie jest taki sam dla wszystkich.
Mam nadzieję, że to wam pomoże. Właściwie chciałem wygenerować przypadek testowy, w którym == kończy się niepowodzeniem i równa się () przejściu. Skomentuj i daj mi znać, jeśli się mylę.
mango == mango2
dzieje się tak, ponieważ nie utworzono mango2
nowego obiektu String, a zamiast tego bezpośrednio się do niego odwołuje "mango"
?
W == testy operatorskie czy dwie zmienne mają takie same oznaczenia (aka wskaźnik do adresu pamięci) .
String foo = new String("abc");
String bar = new String("abc");
if(foo==bar)
// False (The objects are not the same)
bar = foo;
if(foo==bar)
// True (Now the objects are the same)
Natomiast metoda equals () sprawdza, czy dwie zmienne odnoszą się do obiektów o tym samym stanie (wartościach) .
String foo = new String("abc");
String bar = new String("abc");
if(foo.equals(bar))
// True (The objects are identical but not same)
Twoje zdrowie :-)
Będziesz musiał zastąpić funkcję równości (wraz z innymi), aby użyć jej z niestandardowymi klasami.
Metoda równa porównuje obiekty.
==
Operatora binarnego porównuje adresy pamięci.
String w1 ="Sarat";
String w2 ="Sarat";
String w3 = new String("Sarat");
System.out.println(w1.hashCode()); //3254818
System.out.println(w2.hashCode()); //3254818
System.out.println(w3.hashCode()); //3254818
System.out.println(System.identityHashCode(w1)); //prints 705927765
System.out.println(System.identityHashCode(w2)); //prints 705927765
System.out.println(System.identityHashCode(w3)); //prints 366712642
if(w1==w2) // (705927765==705927765)
{
System.out.println("true");
}
else
{
System.out.println("false");
}
//prints true
if(w2==w3) // (705927765==366712642)
{
System.out.println("true");
}
else
{
System.out.println("false");
}
//prints false
if(w2.equals(w3)) // (Content of 705927765== Content of 366712642)
{
System.out.println("true");
}
else
{
System.out.println("false");
}
//prints true
Pamiętaj tylko, że .equals(...)
musi to zostać zaimplementowane przez klasę, którą próbujesz porównać. W przeciwnym razie nie ma większego sensu; wersja metody dla klasy Object robi to samo, co operacja porównania: Object # jest równy .
Jedynym momentem, w którym naprawdę chcesz użyć operatora porównania dla obiektów, jest porównanie Enums. Jest tak, ponieważ istnieje tylko jedna instancja wartości Enum na raz. Na przykład biorąc pod uwagę wyliczenie
enum FooEnum {A, B, C}
Nigdy nie będziesz mieć więcej niż jednego wystąpienia A
naraz i to samo dla B
i C
. Oznacza to, że możesz napisać taką metodę:
public boolean compareFoos(FooEnum x, FooEnum y)
{
return (x == y);
}
I nie będziesz mieć żadnych problemów.
Kiedy oceniasz kod, jest bardzo jasne, że (==) porównuje według adresu pamięci, podczas gdy equals (Object o) porównuje hashCode () instancji. Dlatego mówi się, aby nie łamać umowy między equals () i hashCode (), jeśli później nie spotka Cię niespodzianka.
String s1 = new String("Ali");
String s2 = new String("Veli");
String s3 = new String("Ali");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println("(s1==s2):" + (s1 == s2));
System.out.println("(s1==s3):" + (s1 == s3));
System.out.println("s1.equals(s2):" + (s1.equals(s2)));
System.out.println("s1.equal(s3):" + (s1.equals(s3)));
/*Output
96670
3615852
96670
(s1==s2):false
(s1==s3):false
s1.equals(s2):false
s1.equal(s3):true
*/
Oto ogólna zasada dotycząca różnicy między relational operator ==
i the method .equals()
.
object1 == object2
porównuje, czy obiekty, do których odwołują się obiekty object1 i object2, odnoszą się do tej samej lokalizacji pamięci w Heap .
object1.equals(object2)
porównuje wartości object1 i object2 niezależnie od tego, gdzie znajdują się w pamięci .
Można to dobrze zademonstrować za pomocą String
Scenariusz 1
public class Conditionals {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = new String("Hello");
System.out.println("is str1 == str2 ? " + (str1 == str2 ));
System.out.println("is str1.equals(str2) ? " + (str1.equals(str2 )));
}
}
The result is
is str1 == str2 ? false
is str1.equals(str2) ? true
Scenariusz 2
public class Conditionals {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
System.out.println("is str1 == str2 ? " + (str1 == str2 ));
System.out.println("is str1.equals(str2) ? " + (str1.equals(str2 )));
}
}
The result is
is str1 == str2 ? true
is str1.equals(str2) ? true
To porównanie ciągów może być wykorzystane jako podstawa do porównania innych typów obiektów.
Na przykład, jeśli mam klasę Person , muszę zdefiniować podstawę kryteriów, na podstawie której porównam dwie osoby . Powiedzmy, że ta klasa osób ma zmienne instancji wzrostu i wagi.
Więc tworząc obiekty osoby person1 and person2
i porównując te dwa za pomocą .equals()
I, muszę przesłonić metodę równości klasy person aby zdefiniować na podstawie zmiennych instancji (wysokość lub waga), jakie będzie porównanie.
Jednak == operator will still return results based on the memory location of the two objects(person1 and person2)
.
Dla ułatwienia uogólnienia porównania obiektów tej osoby stworzyłem następującą klasę testową. Eksperymentowanie z tymi koncepcjami ujawni mnóstwo faktów .
package com.tadtab.CS5044;
public class Person {
private double height;
private double weight;
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(height);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
/**
* This method uses the height as a means of comparing person objects.
* NOTE: weight is not part of the comparison criteria
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (Double.doubleToLongBits(height) != Double.doubleToLongBits(other.height))
return false;
return true;
}
public static void main(String[] args) {
Person person1 = new Person();
person1.setHeight(5.50);
person1.setWeight(140.00);
Person person2 = new Person();
person2.setHeight(5.70);
person2.setWeight(160.00);
Person person3 = new Person();
person3 = person2;
Person person4 = new Person();
person4.setHeight(5.70);
Person person5 = new Person();
person5.setWeight(160.00);
System.out.println("is person1 == person2 ? " + (person1 == person2)); // false;
System.out.println("is person2 == person3 ? " + (person2 == person3)); // true
//this is because perosn3 and person to refer to the one person object in memory. They are aliases;
System.out.println("is person2.equals(person3) ? " + (person2.equals(person3))); // true;
System.out.println("is person2.equals(person4) ? " + (person2.equals(person4))); // true;
// even if the person2 and person5 have the same weight, they are not equal.
// it is because their height is different
System.out.println("is person2.equals(person4) ? " + (person2.equals(person5))); // false;
}
}
Wynikiem wykonania tej klasy jest:
is person1 == person2 ? false
is person2 == person3 ? true
is person2.equals(person3) ? true
is person2.equals(person4) ? true
is person2.equals(person4) ? false
== operator zawsze porównuje odniesienie. Ale w przypadku
metoda równa się ()
to zależy od implementacji, jeśli mamy przesłoniętą metodę równości, niż porównuje obiekt z podstawową implementacją podaną w przesłoniętej metodzie.
class A
{
int id;
String str;
public A(int id,String str)
{
this.id=id;
this.str=str;
}
public static void main(String arg[])
{
A obj=new A(101,"sam");
A obj1=new A(101,"sam");
obj.equals(obj1)//fasle
obj==obj1 // fasle
}
}
w powyższym kodzie zarówno obiekt obj, jak i obiekt obj1 zawierają te same dane, ale odwołanie nie jest takie samo, więc równa się również false i ==. ale jeśli zastąpimy metodę równa się niż
class A
{
int id;
String str;
public A(int id,String str)
{
this.id=id;
this.str=str;
}
public boolean equals(Object obj)
{
A a1=(A)obj;
return this.id==a1.id;
}
public static void main(String arg[])
{
A obj=new A(101,"sam");
A obj1=new A(101,"sam");
obj.equals(obj1)//true
obj==obj1 // fasle
}
}
Wiem, sprawdź, zwróci prawdę i fałsz w tym samym przypadku tylko my zastąpiliśmy
równa się metoda.
porównuje obiekt na podstawie podstawowej treści (id) obiektu
ale ==
nadal porównuj odniesienia do obiektu.
Główną różnicą między == a equals () jest
1) == służy do porównywania prymitywów.
Na przykład :
String string1 = "Ravi";
String string2 = "Ravi";
String string3 = new String("Ravi");
String string4 = new String("Prakash");
System.out.println(string1 == string2); // true because same reference in string pool
System.out.println(string1 == string3); // false
2) equals () służy do porównywania obiektów. Na przykład :
System.out.println(string1.equals(string2)); // true equals() comparison of values in the objects
System.out.println(string1.equals(string3)); // true
System.out.println(string1.equals(string4)); // false
==
można go używać w wielu typach obiektów, ale można go używać Object.equals
w dowolnym typie, zwłaszcza w ciągach znaków i znacznikach mapy Google.
public class StringPool {
public static void main(String[] args) {
String s1 = "Cat";// will create reference in string pool of heap memory
String s2 = "Cat";
String s3 = new String("Cat");//will create a object in heap memory
// Using == will give us true because same reference in string pool
if (s1 == s2) {
System.out.println("true");
} else {
System.out.println("false");
}
// Using == with reference and Object will give us False
if (s1 == s3) {
System.out.println("true");
} else {
System.out.println("false");
}
// Using .equals method which refers to value
if (s1.equals(s3)) {
System.out.println("true");
} else {
System.out.println("False");
}
}
}
---- Wyjście ----- prawda fałsz prawda
Warto dodać, że dla obiektów otoki dla typów pierwotnych - tj. Int, Long, Double - == zwróci true, jeśli obie wartości są równe.
Long a = 10L;
Long b = 10L;
if (a == b) {
System.out.println("Wrapped primitives behave like values");
}
Dla kontrastu, umieszczenie powyższych dwóch Longów w dwóch oddzielnych ArrayLists, równa się, widzi je tak samo, ale == nie.
ArrayList<Long> c = new ArrayList<>();
ArrayList<Long> d = new ArrayList<>();
c.add(a);
d.add(b);
if (c == d) System.out.println("No way!");
if (c.equals(d)) System.out.println("Yes, this is true.");
Long a = 128l; Long b = 128l; System.out.println(a == b);
Basen String (aka interning ) i basen Integer rozmycie różnica dalej, i może pozwolić na wykorzystanie ==
obiektów w niektórych przypadkach zamiast.equals
Może to zapewnić większą wydajność (?), Kosztem większej złożoności.
Na przykład:
assert "ab" == "a" + "b";
Integer i = 1;
Integer j = i;
assert i == j;
Kompromis złożoności: mogą Cię zaskoczyć:
assert new String("a") != new String("a");
Integer i = 128;
Integer j = 128;
assert i != j;
Radzę trzymać się z dala od takiej mikrooptymalizacji i zawsze używać .equals
do obiektów i ==
do prymitywów:
assert (new String("a")).equals(new String("a"));
Integer i = 128;
Integer j = 128;
assert i.equals(j);
Krótko mówiąc, odpowiedź brzmi „tak”.
W Javie ==
operator porównuje dwa obiekty, aby sprawdzić, czy wskazują one na tę samą lokalizację pamięci; podczas gdy .equals()
metoda faktycznie porównuje dwa obiekty, aby sprawdzić, czy mają taką samą wartość obiektu.
Zasadniczo ==
porównuje, jeśli dwa obiekty mają to samo odwołanie na stercie, więc jeśli dwa odniesienia nie zostaną połączone z tym samym obiektem, to porównanie będzie fałszywe.
equals()
jest metodą odziedziczoną z Object
klasy. Ta metoda domyślnie porównuje, jeśli dwa obiekty mają to samo odniesienie. To znaczy:
object1.equals(object2)
<=> object1 == object2
Jeśli jednak chcesz ustalić równość między dwoma obiektami tej samej klasy, powinieneś przesłonić tę metodę. Bardzo ważne jest również przesłonięcie metody, hashCode()
jeśli przesłoniłeśequals()
.
Wdrażaj, hashCode()
gdy ustalanie równości jest częścią umowy Java Object Contract. Jeśli pracujesz z kolekcjami, a nie wdrożyłeś hashCode()
, mogą się zdarzyć dziwne złe rzeczy:
HashMap<Cat, String> cats = new HashMap<>();
Cat cat = new Cat("molly");
cats.put(cat, "This is a cool cat");
System.out.println(cats.get(new Cat("molly"));
null
zostanie wydrukowany po wykonaniu poprzedniego kodu, jeśli nie został zaimplementowany hashCode()
.
Ponieważ Java nie obsługuje przeciążania operatorów, == zachowuje się identycznie dla każdego obiektu, ale equals () jest metodą, którą można zastąpić w Javie, a logikę porównywania obiektów można zmieniać w oparciu o reguły biznesowe.
Główną różnicą między == i equals w Javie jest to, że „==” służy do porównywania prymitywów, a metoda equals () jest zalecana do sprawdzania równości obiektów.
Porównanie ciągów jest częstym scenariuszem używania metody == i równości. Ponieważ przesłonięcie klasy java.lang.String jest równe metodzie, Zwraca true, jeśli dwa obiekty String zawierają tę samą treść, ale == zwróci true tylko wtedy, gdy dwa odwołania wskazują na ten sam obiekt.
Oto przykład porównania dwóch ciągów w Javie pod kątem równości za pomocą metody == i equals (), które rozwieją pewne wątpliwości:
public class TEstT{
public static void main(String[] args) {
String text1 = new String("apple");
String text2 = new String("apple");
//since two strings are different object result should be false
boolean result = text1 == text2;
System.out.println("Comparing two strings with == operator: " + result);
//since strings contains same content , equals() should return true
result = text1.equals(text2);
System.out.println("Comparing two Strings with same content using equals method: " + result);
text2 = text1;
//since both text2 and text1d reference variable are pointing to same object
//"==" should return true
result = (text1 == text2);
System.out.println("Comparing two reference pointing to same String with == operator: " + result);
}
}