Comparing String and Integer with equals - java

The output of the below code is false
String str = "3456";
String str1 = "3456";
System.out.println(Integer.valueOf(str).equals(str1));
I didn't understand it. I thought it will return true. As I am preparing for SCJP, understanding the reason behind it may be helpful. Can someone please help?

An Integer will never be equal to a String.
Both classes have very strict equals() definitions that only accept objects of their respective types.
Integer.equals():
The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
String.equals():
The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
That's actually a quite common way to implement equals(): only objects of the same class (and occasionally subclasses) can be equal. Other implementations are possible, but are the exception.
One common exception are the collections such as List: every List implementation that follows the convention will return true when compared to any other implementation, if it has the same content in the same order.

Usually, when implementing equals(), one of the first things to do is to check whether the objects are of one and the same type.
public boolean equals(Object obj) {
if (!(obj instanceof SomeType)) return false;
...
}
This is also applied in the Integer and String classes, which answers the question why do you receive false as a result.

The general contract of the equals() methods states (among other things) that the objects that are being compared need to be of the same class. That's why you'll never be able to compare Apples with Oranges.
For the full contract of the equals() method, see the javadocs.

a Integer Object can't equals with String Object
use :
boolean a = str.equals(str1);
OR
boolean a = (Integer.parseInt(str) == Integer.parseInt(str1));

Related

Is == guaranteed to return correct result? [duplicate]

This question already has answers here:
Compare two objects with .equals() and == operator
(16 answers)
Closed 1 year ago.
From what I understand, the == operator in Java compares references (an int) of objects.
This value is what the default implementation of hashCode method in Object returns.
The hashCode method has an implementation note:
As far as is reasonably practical, the hashCode method defined
by class Object returns distinct integers for distinct objects.
reasonably practical: This means that, no matter how small, there is a real possibility that two distinct objects can have equal hashCode or reference value.
So, if I compare two different objects (that don't override hashCode and equals) using ==, it's a real possibility that the result can be true (?). The default implementation of equals does a == check:
public class Test {
public static void main(String[] args) {
var t1 = new Test();
var t2 = new Test();
System.out.println(t1.hashCode() + ":" + t2.hashCode()); // 2055281021:1554547125 (Could've been 1554547125:1554547125 ?)
System.out.println(t1 == t2); // false (Could've been true ?)
System.out.println(t1.equals(t2)); // false (Could've been true ?)
}
}
Why is that equals and hashCode are overridden in certain situations only and rest of the time (many library classes such as Thread) depend on default implementation for equality check when it's not guaranteed to return correct result?
And, how someone extremely risk-averse make sure the above false-positive would never occur? If the class has at least one non-static field, one can override hashCode and equals. But, what if this is not the case (like the Test class above)?
Can you please explain what am I missing here?
Edit 1:
Adding an API note for hashCode (taken form Silvio's answer):
This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language
Okay, there's a lot of questions here, so let's try to break it down.
From what I understand, the == operator in Java compares references (an int) of objects.
This value is what the default implementation of hashCode method in Object returns.
== in Java compares references, yes. Those references are not necessarily compatible with int. On many common architectures, int will probably coincide with most of the observable space that a reference can occupy, but that's not true in general.
In particular.
int is a signed type. That means half of its values are negative. Pointers are generally unsigned.
Even if we ignore the sign problems, int is a 32-bit type. Most modern computers are 64-bit, which means the address space would fit better in a 64-bit integer (i.e. a Java long). So only a small fraction of addresses can even be stored in int.
Second, hashCode is not required to have anything to do with the pointer itself. From the hashCode docs you referenced already
(This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
A Java implementation is free to choose whatever hashCode it wants. Maybe you're running on some bizarre embedded hardware and it makes sense to use some additional flag variable in the computation. hashCode should not be assumed to be the pointer.
Why is that equals and hashCode are overridden in certain situations only and rest of the time (many library classes such as Thread) depend on default implementation for equality check when it's not guaranteed to return correct result?
What is your definition of "correct" here? The guarantees demanded by the Java specification can be summarized from the docs
The equals method implements an equivalence relation on non-null object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
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.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
...
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.
The default equals implementation clearly satisfies the basic requirements above, and the default hashCode is guaranteed by the standard to be the same for two equal objects.
We override equals when we have a better notion of equality. For instance, two strings should be considered equal if they have the same characters, even if they are distinct objects in memory, and two array lists should be equal if their elements are equal pointwise. But for something like Thread, what would that even mean? When should two arbitrary threads be equal? The default suffices well enough, because we'd gain nothing from overriding it anyway.
If the class has at least one non-static field, one can override hashCode and equals
What does equality have to do with the number of non-static fields? I can override the two just fine. Watch.
public final class MySimpleClass {
public boolean equals(Object other) {
return (other != null) && (other instanceof MySimpleClass);
}
public int hashCode() {
return 42;
}
}
That's a perfectly valid, conformant implementation of equality and hashing for MySimpleClass. In particular, since there's only one meaningfully distinct value of this class, I'd argue that's a good implementation of the two methods. No non-static fields required.
== always returns false if you compare 2 different objects and always returns true if you compare an object to itself.
But it is not guaranteed, that 2 different objects return different hash codes. That's because hashCode() returns int and there's only about 4 billion distinct ints. The number of objects in your code is constrained by the size of heap only.
So, because there can be more than 4 billion distinct objects, their hash codes can sometimes be the same
As for equals, it works as == by default, but can be overridden, so == can return false, when equals returns true and vice versa
equals and hashCode have an unenforceable-at-compile-time contract between them (which itself is different than the == operator).
Fundamentally speaking, an object should override hashCode such that a.equals(b) (and its inverse) is congruent to a.hashCode() == b.hashCode() (and its inverse).
The == operator is only looking to compare numeric equality, which is why the same instance of an object compared against itself (or a == a) will return true, with some caveats given to Strings and string interning.
Because the contract between equals and hashCode is unenforceable, suggesting that == will always return a "correct" result depends on your definition of "correct".
For instance:
It's correct that a square is a parallelogram; it's not correct that any given square is the same as any given parallelogram.
It's correct that a book is a dictionary; it's not correct that any given book is a dictionary.
It's correct that a car has wheels; it's not correct that any given car has any given number of wheels.
Also too - just remember that hashCode is only 32 bits, so there's always going to be the chance of a collision between two unrelated objects (which is where having equals pick up the slack is beneficial here).
In this context, you can only trust == based on the constraints and conditions the individual object has, and what business rules make sense for equality comparisons given a hash code, and nothing further. If your business rules require a deviation between how equals and hashCode behave, then you have to keep that context in mind when comparing through those methods.
Firstly, == checks the memory reference. JVM does this using pointers internally. So each object is literally different as they are stored in different memory address. As compared using memory address location 32 or 64 bit int/number.
For your second question, if you need to have a hash code implementation, but the class has no fields. Then use System.identityHashCode() to do it. It will provide zero for null object and a unique/smal hashcode for same object.
From what I understand, the == operator in Java compares references
(an int) of objects.
On a 64-bit architecture, a reference will need 8 bytes. This is a long, not an int.
This value is what the default implementation of hashCode method in Object returns.
When you cast a long to an int, you will lose information. This is why the default implementation of hashCode() can return equal hashes for different objects.

Trying to compare two strings in Java using equals()

I have tried a number of ways to compare two strings of 'phone numbers' and none seem to pass the tests.
the code I am currently using:
public boolean equals (PhoneNumber other) {
boolean results = other.equals(digits);
return results;
}
The test I am trying to pass without hard coding for it:
p = new PhoneNumber("5551212");
p2 = new PhoneNumber("5551212", "Home");
displayResults(p.equals(p2));
p.setDigits("1234123");
displayResults(p.equals(p2) == false);
Two separate problems:
[1] digits is a string; other is a phonenumber. these will NEVER be equal. What you're presumably looking for, is other.digits.equals(this.digits). Now we're comparing the digits of phone number A with the digits of phone number B: Apples and apples. That has a chance of working out.
[2] the equals method's signature is public boolean equals(Object other). Your equals method has a different signature, which means, it is an entirely different method with no relation whatsoever to the real equals method.. other than the coincidence that it so happens to share a name with it. It means your 'fake' equals method would not be used by other code that uses equals methods. Such as the contains method of an arraylist, for example. The solution is to make that equals method have as argument Object other.
[3] when you do that, you won't be able to call .digits on other; after all, only phonenumbers have digits; any random object isn't guaranteed to. The solution is to cast the other, but only do that after checking if it is a phonenumber:
public boolean equals(PhoneNumber other) {
if (!(other instanceof PhoneNumber)) {
// somebody is comparing apples to oranges. Obviously, then...
return false;
}
return ((PhoneNumber) other).digits.equals(this.digits);
}
note also that for proper operation of such an object in, say, HashSet, you must always override both the hashCode and the equals method, or neither.
Project Lombok automates all this stuff, you may be interested in this.

Why Set is allowing duplicate Byte Integer and Long values

As my knowledge set basically have two methods equals() and hashcode(),based on which its determining the values contains are equal and avoiding duplicate entry,but below program where i get confused,even wrapper classes also have both methods overridden then why its accepting duplicate values?
Code:
Collection col=new LinkedHashSet();
col.add(new Long(65));
col.add(new Byte((byte) 65));
col.add(new Integer(65));
col.add("A");
System.out.println(col);
Answer: [65,65,65,A]
But I expected [65,A]
A Long instance can never be equal to an Integer instance which can never be equal to a Byte instance, even if both have the same numeric value. The 3 instances you put in your Set are not equal to each other.
See, for example, Integer's equals :
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Both instances must be of the same type in order to be equal to each other (a necessary condition).
Here is what the javadoc for Integer.equals(Object) says:
Compares this object to the specified object. The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
In other words, an Integer object cannot be equal to an object that is not also an Integer object. The same applies to all of the primitive wrapper classes.
Thus, those 4 objects in your example are not equal, and hence not duplicates, according to the semantics of HashSet.
Unfortunately, if you are using HashSet or any other of the standard Java hashtable-based classes, together with the standard wrapper classes, there is no workaround for this.
However:
If you were to use TreeSet or similar, you could work around this issue using a custom Comparator object.
There is an alternative hash table implementation in Guava that allows you to supply external equals and hashCode implementations.
You could create your own wrapper classes with different semantics for equals and hashcode to the standard classes. Unfortunately, these would not interoperate with other things; e.g. Java auto-boxing / auto-unboxing.
Set does not allow duplicate values. The question here is what is duplicate and what is not.
Duplicate values are those thatare of the same type, have the same hashCode() and also return true when being compared. Objects of different types (in your case Byte and Long) are not equal in these terms.
If you want however to put values of different numeric types into Set and enjoy cross-type behavior, you can use TreeSet with your custom Comparator that compares values only without taking the type into consideration.

How should I override equals and hashcode method to avoid adding equal objects o HashSet?

I have studied similar examples and override these methods like this, but still get added to the HashSet<NamedObject> objects with the equal names BUT different id.
public class NamedObject {
String name;
BigInteger id;
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NamedObject that = (NamedObject) o;
return this.name.equals(that.getName());
}
#Override
public int hashCode() {
return id.hashCode();
}
}
I have studied similar examples and override these methods like this, but still get added to the HashSet<NamedObject> objects with the equal names BUT different id.
Yes, because you're only using the id in the hash code, and only using the name in the equality check. HashSet<> will only call equals() when it finds an existing object with the same hash code as the one you're trying to add... if your IDs are different, it's highly unlikely that the hash codes will be different, so it's never calling equals with the object that has the same name.
Your hashCode() and equals() methods must be consistent with each other. You need to decide whether equality is based on name, ID, or both - and then use that in both hashCode() and equals().
From the Object.hashCode() documentation:
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.
Your methods break the middle of these requirements at the moment.

Is Java's assertEquals method reliable?

I know that == has some issues when comparing two Strings. It seems that String.equals() is a better approach. Well, I'm doing JUnit testing and my inclination is to use assertEquals(str1, str2). Is this a reliable way to assert two Strings contain the same content? I would use assertTrue(str1.equals(str2)), but then you don't get the benefit of seeing what the expected and actual values are on failure.
On a related note, does anyone have a link to a page or thread that plainly explains the problems with str1 == str2?
You should always use .equals() when comparing Strings in Java.
JUnit calls the .equals() method to determine equality in the method assertEquals(Object o1, Object o2).
So, you are definitely safe using assertEquals(string1, string2). (Because Strings are Objects)
Here is a link to a great Stackoverflow question regarding some of the differences between == and .equals().
assertEquals uses the equals method for comparison. There is a different assert, assertSame, which uses the == operator.
To understand why == shouldn't be used with strings you need to understand what == does: it does an identity check. That is, a == b checks to see if a and b refer to the same object. It is built into the language, and its behavior cannot be changed by different classes. The equals method, on the other hand, can be overridden by classes. While its default behavior (in the Object class) is to do an identity check using the == operator, many classes, including String, override it to instead do an "equivalence" check. In the case of String, instead of checking if a and b refer to the same object, a.equals(b) checks to see if the objects they refer to are both strings that contain exactly the same characters.
Analogy time: imagine that each String object is a piece of paper with something written on it. Let's say I have two pieces of paper with "Foo" written on them, and another with "Bar" written on it. If I take the first two pieces of paper and use == to compare them it will return false because it's essentially asking "are these the same piece of paper?". It doesn't need to even look at what's written on the paper. The fact that I'm giving it two pieces of paper (rather than the same one twice) means it will return false. If I use equals, however, the equals method will read the two pieces of paper and see that they say the same thing ("Foo"), and so it'll return true.
The bit that gets confusing with Strings is that the Java has a concept of "interning" Strings, and this is (effectively) automatically performed on any string literals in your code. This means that if you have two equivalent string literals in your code (even if they're in different classes) they'll actually both refer to the same String object. This makes the == operator return true more often than one might expect.
In a nutshell - you can have two String objects that contain the same characters but are different objects (in different memory locations). The == operator checks to see that two references are pointing to the same object (memory location), but the equals() method checks if the characters are the same.
Usually you are interested in checking if two Strings contain the same characters, not whether they point to the same memory location.
public class StringEqualityTest extends TestCase {
public void testEquality() throws Exception {
String a = "abcde";
String b = new String(a);
assertTrue(a.equals(b));
assertFalse(a == b);
assertEquals(a, b);
}
}
The JUnit assertEquals(obj1, obj2) does indeed call obj1.equals(obj2).
There's also assertSame(obj1, obj2) which does obj1 == obj2 (i.e., verifies that obj1 and obj2 are referencing the same instance), which is what you're trying to avoid.
So you're fine.
Yes, it is used all the time for testing. It is very likely that the testing framework uses .equals() for comparisons such as these.
Below is a link explaining the "string equality mistake". Essentially, strings in Java are objects, and when you compare object equality, typically they are compared based on memory address, and not by content. Because of this, two strings won't occupy the same address, even if their content is identical, so they won't match correctly, even though they look the same when printed.
http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/
"The == operator checks to see if two Objects are exactly the same Object."
http://leepoint.net/notes-java/data/strings/12stringcomparison.html
String is an Object in java, so it falls into that category of comparison rules.

Categories