Confusion with equal method - java

Whenever I use equals() method with two different StringBuffer objects, I get the result as false, but when I use equals() method with two different String objects, I get the result as true. Why?
String s=new String("434");
String s1=new String("434");
System.out.println(s.equals(s1));//true
StringBuffer s=new StringBuffer("434");
StringBuffer s1=new StringBuffer("434");
System.out.println(s.equals(s1));//false

StringBuffer does not override equals(). As such, Object.equals() is called, which compare the object identity (the memory address). String does override equals and compare the content.

StringBuffer does not override Object#equals(), so you're experiencing reference identity-based checks rather than value-based checks. As these StringBuilder instances are distinct, each with different memory locations, the base Object#equals() implementation will always return false.
Here's the definition as of Java 6:
public boolean equals(Object obj) {
return (this == obj);
}
See the problem?

At least in my version of the JDK (Sun 1.6), StringBuffer does not implement an equals() method. This means it inherits Object's equals() method, which is the same as ==
If you really want to test two StringBuffers for equality, you could call x.toString().equals(y.toString())

If what you are looking to do is compare the String representations of the two StringBuffer objects, then what you want to do is:
StringBuffer sb1 = new StringBuffer("434");
StringBuffer sb2 = new StringBuffer("434");
if (sb1.toString().equals(sb2.toString())) {
// whatever you want to do if they're equal
} else {
// whatever you want to do if they're not
}
Otherwise, you're comparing for equality of the two StringBuffer objects, not their contents -- in other words, executing Object#equals(), not (the non-existent) StringBuffer#equals().

equals only returns true on StringBuffer objects when the two objects are the same. To compare StringBuffers the way you want, use this:
System.out.println(s.toString().equals(s1.toString());

String s.equals will use the string table to compare the actual strings where as the StringBuffer sb.equals will just use the default implementation of the equals method and just compare the object pointers.

StringBuffer doesn't have it's own implemention of equals method it inherits the equals() method from the object class hence the hashvalues are compared rather than comparing the actual content in the stringBuffer. Hence we have to explicitly cast it to a string object which provides the implementation for equals() method.

The semantics of the String object are such that if two instances are ever observed to contain the same sequence of characters, they will always contain the same sequence of characters and one could--at least from the standpoint of the String object itself--replace all references to one of the strings with references to the other without changing program semantics. Such instances may be considered equivalent, because for all practical purpose, the only information encapsulated in an instance of String is the sequence of characters contained in the target instance.
By contrast, a variable of type StringBuffer encapsulates not just a sequence of characters, but also the identity of a particular instance. If two variables refer to the same instance, changing to the instance referred to by one variable will affect the instance referred to by the other (since it's the same instance). If they refer to different instances, changes to the instance referred to by one will not affect the instance referred to by the other. The decision not to have Java's StringBuffer override equals wasn't a result of laziness, but was rather based upon the fact that StringBuffer objects have a meaningful identity, and disjoint instances always have different identities.

Related

String str1=new String("abc"); String str2="abc" returning same hashcode

I am trying the attached code. I thought the below two references were different but does the attached output shows the same hashcode? I was in the assumption that both are different?
Are they different in anyways?
String str1=new String("abc");
String str3="abc";
Below is the code from Eclipse with output
Don't confuse "same hashcode" with "same reference". For Object (and any class that does not override hashCode) the hashcode does represent something like the memory address,1) but in general, objects that are equal (even if not the same) should have the same hashCode.
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
System.out.println(s1.hashCode()); // 96354
System.out.println(s2.hashCode()); // 96354
System.out.println(s3.hashCode()); // 96354
That does not mean that they are the same, though. While s1 and s2 are the same (pooled) string, i.e. the same object in memory, new String will indeed create a different (but equal) object.
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1.equals(s3)); // true
If you want to get a different hash code for different objects, like for Object.hashCode,1) you can use System.identityHashcode.
System.out.println(System.identityHashCode(s1)); // 225534817
System.out.println(System.identityHashCode(s2)); // 225534817
System.out.println(System.identityHashCode(s3)); // 1878246837
1) Which might be the actual memory address, but this is not part of the "contract" of the method, i.e. more of an implementation detail. In particular, this value stays the same over the lifetime of the object even if its memory location should change (thanks to Mark for pointing this out).
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method,
then calling the hashCode method on each of the two objects must
produce the same integer result.
It is not required that if two objects are unequal according to the
equals(java.lang.Object) method, then calling the hashCode method on
each of the two objects must produce distinct integer results.
However, the programmer should be aware that producing distinct
integer results for unequal objects may improve the performance of
hash tables.
So if str1.equals(str3) is true, str1.hashCode() must be equal to str2.hashCode()
The object reference of "str1" and "str3" will still be different. However, the hashcode will be similar because of the hashcode (method) implementation of String class. Point to note here is that, object reference is different from object hashcode. And, it is possible that two objects (with different reference) might have similar hashcode, based on the implementation of hashcode method.
"str1" will be stored inside heap, while "str3" will be stored inside StringPool (which itself is part of heap).

Why does Java need equals() if there is hashCode()?

If two objects return same hashCode, doesn't it mean that they are equal? Or we need equals to prevent collisions?
And can I implement equals by comparing hashCodes?
If two objects have the same hashCode then they are NOT necessarily equal. Otherwise you will have discovered the perfect hash function. But the opposite is true - if the objects are equal, then they must have the same hashCode.
hashCode and Equals are different information about objects
Consider the analogy to Persons where hashcode is the Birthday,
in that escenario, you and many other people have the same b-day (same hashcode), all you are not the same person however..
Why does Java need equals() if there is hashCode()?
Java needs equals() because it is the method through which object equality is tested by examining classes, fields, and other conditions the designer considers to be part of an equality test.
The purpose of hashCode() is to provide a hash value primarily for use by hash tables; though it can also be used for other purposes. The value returned is based on an object's fields and hash codes of its composite and/or aggregate objects. The method does not take into account the class or type of object.
The relationship between equals() and hashCode() is an implication.
Two objects that are equal implies that the have the same hash code.
Two objects having the same hash code does not imply that they are equal.
The latter does not hold for several reasons:
There is a chance that two distinct objects may return the same hash code. Keep in mind that a hash value folds information from a large amount of data into a smaller number.
Two objects from different classes with similar fields will most likely use the same type of hash function, and return equal hash values; yet, they are not the same.
hashCode() can be implementation-specific returning different values on different JVMs or JVM target installations.
Within the same JVM, hashCode() can be used as a cheap precursor for equality by testing for a known hash code first and only if the same testing actual equality; provided that the equality test is significantly more expensive than generating a hash code.
And can I implement equals by comparing hashCodes?
No. As mentioned, equal hash codes does not imply equal objects.
The hashCode method as stated in the Oracle Docs is a numeric representation of an object in Java. This hash code has limited possible values (represented by the values which can be stored in an int).
For a more complex class, there is a high possibility that you will find two different objects which have the same hash code value. Also, no one stops you from doing this inside any class.
class Test {
#Override
public int hashCode() {
return 0;
}
}
So, it is not recommended to implement the equals method by comparing hash codes. You should use them for comparison only if you can guarantee that each object has an unique hash code. In most cases, your only certainty is that if two objects are equal using o1.equals(o2) then o1.hashCode() == o2.hashCode().
In the equals method you can define a more complex logic for comparing two objects of the same class.
If two objects return same hashCode, doesn't it mean that they are equal?
No it doesn't mean that.
The javadocs for Object state this:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently
return the same integer, provided no information used in equals
comparisons on the object is modified. ...
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must
produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCodemethod on
each of the two objects must produce distinct integer results. ...
Note the highlighted statement. It plainly says "No" to your question.
There is another way to look at this.
The hashCode returns an int.
There are only 232 distinct values that an int can take.
If a.hashCode() == b.hashCode() implies a.equals(b), then there can be only 232 distinct (i.e. mutually unequal) objects at any given time in a running Java application.
That last point is plainly not true. Indeed, it is demonstrably not true if you have a large enough heap to hold 232 instances of java.lang.Object ... in a 64-bit JVM.
And a third way is to some well-known examples where two different two character strings have the same hashcode.
Given that your assumption is incorrect, the reasoning that follows from it is also incorrect.
Java does need an equals method.
You generally cannot implement equals using just hashCode.
You may be able to use hashCode to implement a faster equals method, but only if calling hashCode twice is faster than comparing two objects. It generally isn't.
hashCodes are equal -> Objects might be equal -> further comparision is required
hashCodes are different -> Object are not equal (if hashCode is implemented right)
That's how equals method are implemented. At first you check if hashCodes are equal. If yes, you need to check class fields to see if it represents the exact same object. If hashCodes are different, you can be sure that objects are not equal.
Sometimes (very often?) you don't!
These answers are not untrue. But they don't tell the whole story.
One example would be where you are creating a load of objects of class SomeClass, and each instance that is created is given a unique ID by incrementing a static variable, nInstanceCount, or some such, in the constructor:
iD = nInstanceCount++;
Your hash function could then be
int hashCode(){
return iD;
}
and your equals could then be
boolean equals( Object obj ){
if( ! ( obj instanceof SomeClass )){
return false;
}
return hashCode() == obj.hashCode();
}
... under such circumstances your idea that "equals is superfluous" is effectively true: if all classes behaved like this, Java 10 (or Java 23) might say, ah, let's just get rid of silly old equals, what's the point? (NB backwards compatibility would then go out the window).
There are two essential points:
you couldn't then create more than MAXINT instances of SomeClass. Or... you could ... if you set up a system for reassigning the IDs of previously destroyed instances. IDs are typically long rather than int ... but this wouldn't work because hashCode() returns int.
none of these objects could then be "equal" to another one, since equality = identity for this particular class, as you have defined it. Often this is desirable. Often it shuts off whole avenues of possibilities...
The necessary implication of your question is, perhaps, what's the use of these two methods which, in a rather annoying way, have to "cooperate"? Frelling, in his/her answer, alluded to the crucial point: hash codes are needed for sorting into "buckets" with classes like HashMap. It's well worth reading up on this: the amount of advanced maths that has gone into designing efficient "bucket" mechanisms for classes like HashMap is quite frightening. After reading up on it you may come to have (like me) a bit of understanding and reverence about how and why you should bother implementing hashCode() with a bit of thought!

How do I check in Java whether two references are holding the same object? [duplicate]

This question already has answers here:
Comparing references in Java
(5 answers)
Closed 7 years ago.
I am looking for a Java equivalent of pointer-comparison in C/C++.
Suppose I am invoking a getSomething() method of an object of a class from a third-party. How do I know if the implementation of the getSomething() is just returning the same instance everytime or returning a different instance of the object?
I am not looking to check whether two objects are identical, but need to check if they are the same instance or not. The motivation is, if the 3rd party implementation is creating a new instance everytime, probably I can optimize my code by not invoking the method everytime. Assume getSomething() is invoked by me 1000s of times a second at run-time
From what I read from various articles, I shouldn't rely on hashCode(). In that case what is the way to do this?
Reference types are "pointing to" the same object, when they are equivalent according to the == (identity) operator.
The question says:
I am not looking to check whether two objects are identical, but need to check if they are the same instance or not (emphasis mine)
You actually mixed equality with identity (as I did initially in the answer). Being the same instance is identity. Being the same value is equality.
The == operator compares the values held by the two operands. If the operands are primitive, the actual values are checked for equality. If the operands are of object type, then == checks for equality of identity, functioning in this role just like Python's is keyword.
Note that there is bit of fudginess caused by autboxing and autounboxing between primitive and wrapper object types.
== double equal operator are use to check whether two reference variable hold the same object or not.
Eg.
String s1 = new String("hello");
String s2 = s1;
String s3 = new String("hello");
System.out.println(s1==s2); // it prints true
System.out.println(s1==s3); // it prints false
s1 and s2 pointing to the same object.
s3 holds newly created object and hence s1 == s3 prints false
I think you're not looking for the ==operator. To compare two instances of an object, for example, I use the equals() Object method. Here are two useful links about comparisons:
java ==, equals(), compare(), compareTo()
Javadocs equals() method
You can use == operator to compare two objects if they are having same reference or not.

Java string comparison is not working when concatenated with number

My question to java folks is, when I am comparing two strings
imageName=new String[20];
....
imageName[1]="img1";
imageName[2]="img1";
if(imageName[1]==imageName[2])
{
//// codes
}
it works perfectly, but when I am making the string through number concatenation it's not working
imageName=new String[20];
int j=1,k=1;
imageName[1]="img"+j;
imageName[2]="img"+k;
if(imageName[1].toString()==imageName[2].toString())
{
//// codes
}
it's not working though the values of j and k are the same
Thanks in advance for your solution
You should use String.equals when comparing two Strings:
if (imageName[1].equals(imageName[2])
You shouldn't compare strings with ==, but instead use the .equals method: imageName[1].equals(imageName[2]).
== compares the pointers for equality, so it'll be true if both variables represent the exact same instance in memory. In the first case, it's the case because Java pools String literals for performance. But in your second case, you're getting two distinct heap-allocated objects, which, despite their content is identical, are two distinct objects nonetheless.
You are comparing whether the two String are exactly the same object.
What you intended was to compare their contents. I suggest you use .equals instead.
Never, ever, use "==" to compare Strings in Java. Use the equals() method. The == operator checks to see if two String variables are referring to the same location in memory, while the equals() method checks whether two separate String objects contain the same characters. It's this second definition that makes sense here: your String concatenation is creating separate String objects, but we still want to consider them as "equal".
The correct way to compare strings is using equals() method
So, Please change your code as below,
if (imageName[1].equals(imageName[2])
And please consider to do a research in SO before posting, as the questions like this have been answered many times before.
== is a reference comparison. That is, you're determining if the two objects are, in fact, the same object. If you use equals() then that method comparses the contents of the string i.e. do those objects have the same contents (you'll appreciate there is a subtle difference here)
Your first scenario works since the compiler is clever enough to realise that you have the same string twice. i.e. it looks at:
imageName[1]="img1";
imageName[2]="img1";
and determines that your array elements can point to the same object. In your second scenario, that's no longer true.
imageName[1]="img"+j;
imageName[2]="img"+k;
The compiler can't reliably determine that these could be the same string object (quite correctly, too).
So (generally speaking) you should use equals() to compare Strings. You can use the reference equality (it's faster since it comparse the references rather than the string contents), but you have to be absolutely sure about what you're doing (perhaps you're using String.intern() - but there are disadvantages there)
To compare two Strings you better use equals() method
if(imageName[1].equals(imageName[2]))
{
//// codes
}

Difference between the two Java operators: != vs !equals

Is this code:
elem1!=elem2
equivalent to this one?
!elem1.equals(elem2)
It compiles both ways, but I'm still unsure about it...
== (and by extension !=) check for object identity, that is, if both of the objects refer to the very same instance. equals checks for a higher level concept of identity, usually whether the "values" of the objects are equal. What this means is up to whoever implemented equals on that particular object. Therefore they are not the same thing.
A common example where these two are not the same thing are strings, where two different instances might have the same content (the same string of characters), in which case a == comparison is false but equals returns true.
The default implementation of equals (on Object) uses == inside, so the results will be same for objects that do not override equals (excluding nulls, of course)
In general, no they're not the same. The first version checks whether elem1 and elem2 are references to the same object (assuming that they're not primitive types). The second version calls a type-specific method to check whether two (possibly distinct) ojects are "equal", in some sense (often, this is just a check that all their member fields are identical).
I don't think this has anything to do with generics, as such.

Categories

Resources