Why do != and == not behave like the equals method in Java? [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Java String.equals versus ==
whats the difference between ".equals and =="
public String getName() {
return new String("foobar");
}
if(getName() != "foobar2") {
//Never gets executed, it should, wtf!.
}
if(!getName().equals("foobar2")) {
//This works how it should.
}
So yeah my question is simple.. why doesn't != behave the same as !equals() aka (not Equals).
I don't see any logicial reason why one should fail, both are the same exact code in my mind, WTH.
Looking at java operators
http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
You can clearly see
equality == !=
are the equality operators, sure I usually use != only on numbers.. but my mind started wandering and why doesn't it work for String?
EDIT:
Here's something that looks more like the actual issue..
for (ClassGen cg : client.getClasses().values()) {
final ConstantPoolGen cp = cg.getConstantPool();
if(cp.lookupInteger(0x11223344) != -1) {
for (Method m : cg.getMethods()) {
System.out.println("lots of class spam");
if(m.getName() != "<init>") continue;
System.out.println("NEVER GETS HERE, 100% SURE IT HAS CONSTRUCTOR LOL");
}
}
}

Using != means that you check for the instance reference in the memory, and the same instance will give you true on that comparison.
When you do a new String("foobar"), a new "foobar" is created in the memory, and the comparison using == returns false.
Calling a intern() on that new string may change this behavior, since the String will now be grabbed or added to the String pool.
In any case, it's safer to use the 'equals()'.

public static void main(String[] args) throws Exception {
if (getName() != "foobar2") {
System.out.println("1");
}
if (!getName().equals("foobar2")) {
System.out.println("2");
}
}
public static String getName() {
return new String("foobar");
}
For me this outputs:
1
2
But those two checks are not equivalent. The first check is checking whether the object returned by getName() is the same object that was created for the string literal "foobar2", which it's not. The second check is probably the one you want, and it checks that the VALUE of the String object returned by the getName() method is equal to the VALUE of the String object created for your "foobar2" string literal.
So both checks will return true, the first one because they aren't the same object and the second one because the values aren't the same.

A string is an Object, not a primitive.
== and != compare two primitives to each other.
To compare strings you need to loop trough each character and compare them in order which is what .equals() does.
If you do any OOP in Java you need to override equals when you want to do equality checks on the Objects, and implement Comparable and .compare() if you want to be able to do things like sort them.
Here is a quick example of equals:
public class Person {
public name;
public Person(String name) {
this.name = name;
}
public boolean equals(Object o){
if(o instanceof Person)
if(this.name.equals(o.name))
return true;
return false;
}
}
Now a Person can be compared to another Person like:
person1.equals(person2)
Which will only return true if both people have the same name. You can define what makes two objects equal however you want, but objects are only == if they are really just two pointers to the same object in memory.

Operators only apply to primitives, not Objects, so a String comparison must be done equals, as that operates at the Object level.
--EDIT--
My comment was meant more along the lines of "the value of an Object cannot be compared in the expected way as in other languages". Of course you can use == signs, but not for a textual comparison. This is the classic question that is asked every time someone migrates to Java from a scripting language, or another language that does support operators for text comparison on Strings.

Related

hashCode method in case equals method supports wildchar

I have a class, whose objects will be stored in hashmap, hashset.
I need to support wildchar equality for the fields therefore I have added that check in equals method. Now, how can I build my hashcode method based on this paramter? i.e. if I calculate as shown in code below, I will get different hashcode for 2 objects that pass the equality check of my equals method.
For e.g. consider following class:
public class Person {
private String fname = "";
private String lname = "";
private String profession = "";
// getters & setters
#Override
public boolean equals(Object obj) {
if (fname == null) {
if (other.fname != null)
return false;
} else if (!fname.equals(other.fname) && !other.fname.equals("*") && !fname.equals("*"))
return false;
return true;
// similar for other fields
}
#Override
public int hashCode() {
return Objects.hashCode(this.fname, this.lname , this.profession);
}
}
EDIT:
As pointed out in some of the comments that there should be a separate method to check wildchar equality. The limitation with this approach is I won't be able to get the correct results for methods like set.contains as they check for object.equals internally. So my set.contains will return false, even if my objects passes the equality test of my separate wildchar equality method.
Using the same logic in hashCode() is not possible as we don't compute the hash code according to a compared object but we compute it according to the current object state.
You could return a constant value in the hashCode() method but it would be not efficient and so it doesn't sound a good idea.
Your original issue comes from the fact that you want to give a responsibility not designed to be into the equals() method : defining the equality beyond the actual state of the objects (that is actual field values).
So you should not use the equals() method to perform the wildcard comparison but instead of write a dedicated method for.

compareTo is comparing date but not time JAVA [duplicate]

I constructed a class with one String field. Then I created two objects and I have to compare them using == operator and .equals() too. Here's what I've done:
public class MyClass {
String a;
public MyClass(String ab) {
a = ab;
}
public boolean equals(Object object2) {
if(a == object2) {
return true;
}
else return false;
}
public boolean equals2(Object object2) {
if(a.equals(object2)) {
return true;
}
else return false;
}
public static void main(String[] args) {
MyClass object1 = new MyClass("test");
MyClass object2 = new MyClass("test");
object1.equals(object2);
System.out.println(object1.equals(object2));
object1.equals2(object2);
System.out.println(object1.equals2(object2));
}
}
After compile it shows two times false as a result. Why is it false if the two objects have the same fields - "test"?
== compares object references, it checks to see if the two operands point to the same object (not equivalent objects, the same object).
If you want to compare strings (to see if they contain the same characters), you need to compare the strings using equals.
In your case, if two instances of MyClass really are considered equal if the strings match, then:
public boolean equals(Object object2) {
return object2 instanceof MyClass && a.equals(((MyClass)object2).a);
}
...but usually if you are defining a class, there's more to equivalency than the equivalency of a single field (a in this case).
Side note: If you override equals, you almost always need to override hashCode. As it says in the equals JavaDoc:
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.
You should override equals
public boolean equals (Object obj) {
if (this==obj) return true;
if (this == null) return false;
if (this.getClass() != obj.getClass()) return false;
// Class name is Employ & have lastname
Employe emp = (Employee) obj ;
return this.lastname.equals(emp.getlastname());
}
The best way to compare 2 objects is by converting them into json strings and compare the strings, its the easiest solution when dealing with complicated nested objects, fields and/or objects that contain arrays.
sample:
import com.google.gson.Gson;
Object a = // ...;
Object b = //...;
String objectString1 = new Gson().toJson(a);
String objectString2 = new Gson().toJson(b);
if(objectString1.equals(objectString2)){
//do this
}
The overwrite function equals() is wrong.
The object "a" is an instance of the String class and "object2" is an instance of the MyClass class. They are different classes, so the answer is "false".
It looks like equals2 is just calling equals, so it will give the same results.
Your equals2() method always will return the same as equals() !!
Your code with my comments:
public boolean equals2(Object object2) { // equals2 method
if(a.equals(object2)) { // if equals() method returns true
return true; // return true
}
else return false; // if equals() method returns false, also return false
}
The "==" operator returns true only if the two references pointing to the same object in memory. The equals() method on the other hand returns true based on the contents of the object.
Example:
String personalLoan = new String("cheap personal loans");
String homeLoan = new String("cheap personal loans");
//since two strings are different object result should be false
boolean result = personalLoan == homeLoan;
System.out.println("Comparing two strings with == operator: " + result);
//since strings contains same content , equals() should return true
result = personalLoan.equals(homeLoan);
System.out.println("Comparing two Strings with same content using equals method: " + result);
homeLoan = personalLoan;
//since both homeLoan and personalLoan reference variable are pointing to same object
//"==" should return true
result = (personalLoan == homeLoan);
System.out.println("Comparing two reference pointing to same String with == operator: " + result);
Output:
Comparing two strings with == operator: false
Comparing two Strings with same content using equals method: true
Comparing two references pointing to same String with == operator: true
You can also get more details from the link: http://javarevisited.blogspot.in/2012/12/difference-between-equals-method-and-equality-operator-java.html?m=1
Statements a == object2 and a.equals(object2) both will always return false because a is a string while object2 is an instance of MyClass
Your implementation must like:
public boolean equals2(Object object2) {
if(a.equals(object2.a)) {
return true;
}
else return false;
}
With this implementation your both methods would work.
If you dont need to customize the default toString() function, another way is to override toString() method, which returns all attributes to be compared. then compare toString() output of two objects. I generated toString() method using IntelliJ IDEA IDE, which includes class name in the string.
public class Greeting {
private String greeting;
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
return this.toString().equals(obj.toString());
}
#Override
public String toString() {
return "Greeting{" +
"greeting='" + greeting + '\'' +
'}';
}
}
Your class might implement the Comparable interface to achieve the same functionality. Your class should implement the compareTo() method declared in the interface.
public class MyClass implements Comparable<MyClass>{
String a;
public MyClass(String ab){
a = ab;
}
// returns an int not a boolean
public int compareTo(MyClass someMyClass){
/* The String class implements a compareTo method, returning a 0
if the two strings are identical, instead of a boolean.
Since 'a' is a string, it has the compareTo method which we call
in MyClass's compareTo method.
*/
return this.a.compareTo(someMyClass.a);
}
public static void main(String[] args){
MyClass object1 = new MyClass("test");
MyClass object2 = new MyClass("test");
if(object1.compareTo(object2) == 0){
System.out.println("true");
}
else{
System.out.println("false");
}
}
}
the return type of object.equals is already boolean.
there's no need to wrap it in a method with branches. so if you want to compare 2 objects simply compare them:
boolean b = objectA.equals(objectB);
b is already either true or false.
When we use == , the Reference of object is compared not the actual objects. We need to override equals method to compare Java Objects.
Some additional information C++ has operator over loading & Java does not provide operator over loading.
Also other possibilities in java are implement Compare Interface .which defines a compareTo method.
Comparator interface is also used compare two objects
Here the output will be false , false beacuse in first sopln statement you are trying to compare a string type varible of Myclass type to the other MyClass type and it will allow because of both are Object type and you have used "==" oprerator which will check the reference variable value holding the actual memory not the actual contnets inside the memory .
In the second sopln also it is the same as you are again calling a.equals(object2) where a is a varible inside object1 . Do let me know your findings on this .
In short, == compares two POINTERS.
If the two pointers are equal, then they both point to same object in memory (which, obviously has the same value as itself).
However, .equals will compare the VALUES of whatever is pointed to, returning true iff they both evaluate to the same value.
Thus, two separate strings (i.e., at different addresses in memory) are always != but are .equal iff they contain the same (null-terminated) sequence of chars.
IN the below code you are calling the overriden method .equals().
public boolean equals2(Object object2) {
if(a.equals(object2)) { // here you are calling the overriden method, that is why you getting false 2 times.
return true;
}
else return false;
}

Confusion about Effective Java text

I'm not sure what the author means when he writes that a singleton static factory method can guarantee that no two equal instances exist. Well actually I do kind of understand that but I'm confused by the following text when he demonstrates the equals method vs the literal comparison operator: "a.equals(b) if and only if a==b."
I understand that the equals() method actually compares the contents of an object while the literal == compares to see if they are the same object in memory. This is confusing because he goes on to say that the client can use the == instead of the .equals(object) method. How so? Why would the client use the == comparator if they're guaranteed to only one object?
Could someone write me a short coded example to explain this more concretely?
The authors text is below:
The ability of static factory methods to return the same object from
repeated invocations allows classes to maintain strict control over
what instances exist at any time. Classes that do this are said to be
instance-controlled. There are several reasons to write
instance-controlled classes. Instance control allows a class to
guarantee that it is a singleton (Item 3) or noninstantiable (Item 4).
Also, it allows an immutable class (Item 15) to make the guarantee
that no two equal instances exist: a.equals(b) if and only if a==b. If
a class makes this guarantee, then its clients can use the == operator
instead of the equals(Object) method, which may result in improved
performance. Enum types (Item 30) provide this guarantee.
In the particular snippet you quote at the top he's talking about enforcing one instance for each possible set of values in instances of an immutable class:
Also, it allows an immutable class (Item 15) to make the guarantee
that no two equal instances exist: a.equals(b) if and only if a==b
That is, you might want your static factory to guarantee that if a and b represent the same values, then they are the same instance in memory (i.e. duplicates cannot exist). When this is true, then == works the same as equals(Object), which means that you are free to use == where you think it might help with performance.
As Jon says in the comments, static factories are not restricted to singletons.
I think you've almost got it. The static method makes the following promise, "if you request a new object that would compare .equals() to an existing object, I'll return the existing object instead". Given that guarantee, you know that a.equals(b) means that a == b, and you know that a == b means that a.equals(b). As a result, if you want to see if a and b are equal, you can use the == operator instead of the .equals method. That's useful because == is very fast and, depending on the object types, .equals could be slow.
Here's a concrete example. Suppose we have a person class. A person is defined by their first and last name (pretend that there are no two people in the world with the same name). My class might look like this (didn't try to compile, so no guarantee of correctness):
class Person {
private final String fname;
private final String lname;
// Private constructor - must use the static method
private Person(String first, String last) {fname = first; lname = last;}
// Note that this is slow - the time it takes is proportional to the length of the
// two names
public boolean equals(Object o) {
// Should check types here, etc.
Person other = (Person) o;
if (!person.fname.equals(other.fname)) {return false;}
if (!person.lname.equals(other.lname)) {return false;}
return true;
}
// Registry of all existing people
private static Map<String, Person> registry = new TreeMap<String, Person>();
public static getPerson(String fname, String lname) {
String fullName = fname + "-" + lname;
// If we already have this person, return that object, don't construct a new one.
// This ensures that p1.equals(p2) means that p1 == p2
if (registry.containsKey(fullName)) {return registry.get(fullName);}
Person p = new Person(fname, lname);
registry.put(fullName, p);
return p;
}
}
And then you can use it like this:
public boolean isSamePerson(Person p1, Person p2) {
// Guaranteed to have the same result as "return p1.equals(p2)" but will be faster
return p1 == p2;
}
If you can guarantee (perhaps with a Flyweight pattern) that equal objects will have the same referent, then callers may use == (and get a performance benefit); as an example consider an enum type... you can use == to determine if any two enum instances are the same.

Java .equals() instanceof subclass? Why not call superclass equals instead of making it final?

It is stated in Object's .equals(Object) javadoc:
It is symmetric: for any non-null reference values x and y,
x.equals(y) should return true if and only if y.equals(x) returns
true.
Almost everywhere in example code I see overridden .equals(Object) method which uses instanceof as one of the first tests, for example here: What issues / pitfalls must be considered when overriding equals and hashCode?
public class Person {
private String name;
private int age;
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
...
}
}
Now with class SpecialPerson extends Person having in equals:
if (!(obj instanceof SpecialPerson))
return false;
we con not guarantee that .equals() is symmetric.
It has been discussed for example here: any-reason-to-prefer-getclass-over-instanceof-when-generating-equals
Person a = new Person(), b = new SpecialPerson();
a.equals(b); //sometimes true, since b instanceof Person
b.equals(a); //always false
Maybe I should add in the beginning of SpecialPerson's equals direct call to super?
public boolean equals(Object obj) {
if( !obj instanceof SpecialPerson )
return super.equals(obj);
...
/* more equality tests here */
}
A lot of the examples use instanceof for two reasons: a) it folds the null check and type check into one or b) the example is for Hibernate or some other code-rewriting framework.
The "correct" (as per the JavaDoc) solution is to use this.getClass() == obj.getClass(). This works for Java because classes are singletons and the VM guarantees this. If you're paranoid, you can use this.getClass().equals(obj.getClass()) but the two are really equivalent.
This works most of the time. But sometimes, Java frameworks need to do "clever" things with the byte code. This usually means they create a subtype automatically. Since the subtype should be considered equal to the original type, equals() must be implemented in the "wrong" way but this doesn't matter since at runtime, the subtypes will all follow certain patterns. For example, they will do additional stuff before a setter is being called. This has no effect on the "equalness".
As you noticed, things start to get ugly when you have both cases: You really extend the base types and you mix that with automatic subtype generation. If you do that, you must make sure that you never use non-leaf types.
You are missing something here. I will try to highlight this:
Suppose you have Person person = new Person() and Person personSpecial = new SpecialPerson() then I am sure you would not like these two objects to be equal. So, its really working as required, the equal must return false.
Moreover, symmetry specifies that the equals() method in both the classes must obey it at the same time. If one equals return true and other return false, then I would say the flaw is in the equals overriding.
Your attempt at solving the problem is not correct. Suppose you have 2 subclasss SpecialPerson and BizarrePerson. With this implementation, BizarrePerson instances could be equal to SpecialPerson instances. You generally don't want that.
don't use instanceof. use this.getClass() == obj.getClass() instead. then you are checking for this exact class.
when working with equalsyou should always use the hashCode and override that too!
the hashCode method for Person could look like this:
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
and use it like this in your equals method:
if (this.hashCode() != obj.hashCode())
{
return false;
}
A type should not consider itself equal to an object of any other type--even a subtype--unless both objects derive from a common class whose contract specifies how descendants of different types should check for equality.
For example, an abstract class StringyThing could encapsulate strings, and provide methods to do things like convert to a string or extract substrings, but not impose any requirements on the backing format. One possible subtype of StringyThing, for example, might contain an array of StringyThing and encapsulate the value of the concatenation of all those strings. Two instances of StringyThing would be defined as equal if conversion to strings would yield identical results, and comparison between two otherwise-indistinguishable StringyThing instances whose types knew nothing about each other may have to fall back on that, but StringyThing-derived types could include code to optimize various cases. For example, if one StringyThing represents "M repetitions of character ch" and another represents "N repetitions of the string St", and the latter type knows about the first, it could check whether St contains nothing but M/N repetitions of the character ch. Such a check would indicate whether or not the strings are equal, without having to "expand out" either one of them.

Why are these two instances not `equal()`? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why .equals method is failing on two same value objects?
This is really simple but I'm obviously missing something pretty big here.
Cat cat1 = new Cat("bob");
Cat cat2 = new Cat("bob");
System.out.println(cat1 == cat2);
//false since these references point to diferent objects
System.out.println(cat1.equals(cat2));
//returns false also??
Cat is just a simple class that only has a name.
What is going on here, how does equals() work? I was under the impression that it compared all the fields of the object. It seems that is not the case.
Do I need to overide it for all my classes?
Yes.
java.lang.Object provides very basic implementations of equals() and hashCode(). In particular, they don't go around reflecting on the type of the instance, which would (1) be dreadfully slow, and (2) carry a significant risk of comparing fields that you for various reasons don't want to compare in an equality comparison.
If you want equals() and hashCode() to actually be useful for comparing value equality (rather than reference equality which == does), you'll need to implement both within your own type.
Note that it's not enough to implement just equals(); while technically that will "work", it has the potential to lead to all kinds of weirdness. The simple rule of thumb is: neither or both, but never only one. And they must work on the same fields; if equals() says two instances are equal, then calling hashCode() on both must return the same value (also see the hashCode() contract).
It's also usually a good idea to override toString() with code to provide a meaningful description of the object in question. While not strictly needed, you only need to hit your head against this once in the debugger to realize the value. (Thanks #JonTaylor for mentioning this highly useful, related tidbit.)
And it's .NET that calls it GetHashCode(), while Java uses only hashCode() as the function name...
You need to override equals inside your Cat class. Default equals compares objects on references.
class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Cat))
return false;
Cat c = (Cat) obj;
return this.name == null ? false : this.name.equals(c.name);
}
#Override
public int hashCode() {
return this.name == null ? 31 : this.name.hashCode();
}
#Override
public String toString() {
return "Cat Name :" + name;
}
}
References
equals
hashCode
toString
The equals() provided by java.lang.object compares, simply speaking, a unique identifier for the object, though not entirely accurate you can think of it as a memory location, so it will only be true if you compare an object with itself (i.e. two references to the same object in memory)
You need to implement your own equals() method in your Cat class:
class Cat
{
String name;
#Override
public boolean equals(Cat other)
{
if (this.name.equals(other.name))
return true;
return false;
}
}
It would be wise to override hashCode() also, unless this is just a very basic application for homework or something. Also toString() can be useful to override as well.
http://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html
From [Java Doc]
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).
Without overriding the equals() method, the objects are different
Hence
System.out.println(cat1.equals(cat2)); // is false
That is because the == compare references and java.lang.Object.equals() translates to this==o thus return same as == in your case
In the case above you are using new operator to create two different objects hence both return false.
If you want .equals() to work as you are expecting, then override theequals() in your Cat class.

Categories