Why do we need an Object parameter for equals method? [duplicate] - java

This question already has answers here:
java why should equals method input parameter be Object
(6 answers)
Overloading in Java and multiple dispatch
(6 answers)
Closed 4 years ago.
I was making some tests with the java equals method and I figured out that if my parameter is not of the generic type Object the test won’t pass, even if the two objects I create are of that type. Let’s say I want to check if an object is an animal, what I tried to do is writing down:
public boolean equals(Animal other) {
*some code*
}
And then I create a test for that method to compare the animals. But if I do that the test will fail, on the other side, if I write down:
public boolean equals(Object other) {
*some code*
}
and then test it, the test will pass. I understand that’s useless declaring the object of the desired type and try to test it but I don’t get why it doesn’t work in a good weather test case.

It is simple, Object class equals method signature is this
public boolean equals(Object obj)
But if you write equals method with Animal parameter then it will not be the Overridden equals method from object class. and when you try to compare objects by using .equals() Object class equals will be invoked
For this reason and to make it clear it is always recommended to use #Override annotation

The equals method is part of the base Object class in Java and the only way to make benefit of it is to override it. To override it you need to stick to the same signature which will tell any libraries using equals to invoke your method instead of the base one.
Your above code is doing an overloading which is a totally different method to the Java compiler.

Related

Two objects with same state not retrieving the same value from HashMap [duplicate]

This question already has answers here:
java why should equals method input parameter be Object
(6 answers)
Overloading in Java and multiple dispatch
(6 answers)
Closed 4 years ago.
I was making some tests with the java equals method and I figured out that if my parameter is not of the generic type Object the test won’t pass, even if the two objects I create are of that type. Let’s say I want to check if an object is an animal, what I tried to do is writing down:
public boolean equals(Animal other) {
*some code*
}
And then I create a test for that method to compare the animals. But if I do that the test will fail, on the other side, if I write down:
public boolean equals(Object other) {
*some code*
}
and then test it, the test will pass. I understand that’s useless declaring the object of the desired type and try to test it but I don’t get why it doesn’t work in a good weather test case.
It is simple, Object class equals method signature is this
public boolean equals(Object obj)
But if you write equals method with Animal parameter then it will not be the Overridden equals method from object class. and when you try to compare objects by using .equals() Object class equals will be invoked
For this reason and to make it clear it is always recommended to use #Override annotation
The equals method is part of the base Object class in Java and the only way to make benefit of it is to override it. To override it you need to stick to the same signature which will tell any libraries using equals to invoke your method instead of the base one.
Your above code is doing an overloading which is a totally different method to the Java compiler.

Why isn't my object cast to interface not calling default method? [duplicate]

This question already has answers here:
In Java, why does ((A)b).disp() call derived class method disp() instead of base class method disp() ?
(4 answers)
Closed 3 years ago.
I am learning more about polymorphism and casting in Java. I was running some code and I am quite confused with the output. I would really appreciate it if someone can explain what the compiler is doing here.
When I wrote this code, I thought that since newCar() is being cast to Vehicle, I assumed it would use the default method that was written in the Vehicle interface. But it looks like it used the overridden method in Car.
Thanks in advance!!
public interface Vehicle {
default boolean canFly() {return true;}
}
public class Car implements Vehicle {
boolean canFly() {return false;}
public static void main(String[] args) {
Vehicle vehicle = (Vehicle) new Car();
System.out.println(vehicle.canFly());
}
}
I saw possible duplicates; however, the question was targeted to only classes. My question is specifically with interfaces.
The whole point of inheritance and polymorphing is that it doesn't matter what type the variable has, the actual type of the created object determines which method will be called.
There is no way for you to call the Vehicle version of the canFly method, since it has been overridden by the Car class, and the real object is a Car.
The Lambda faq lists conflict resolution rules for default methods. First rule is:
Classes always win. A declaration in the class or a superclass takes priority over any default method declaration.
Because the class provides an implementation of the method, that always takes precedence over the default method on the interface. ("Default" means a fallback for cases where no implementation is provided otherwise.)
Casting only keeps the compiler from reporting an error due to some variable's type not matching the type of the thing being assigned to it. It's there for cases where you know it's ok to treat something as another type and you need to overrule the compiler. Casting has no effect at runtime, except to cause a ClassCastException to be thrown if the cast is erroneous. See here for more details.
TLDR: The idea that you could use casts to change what method gets called is not accurate.

Testing equality amongst class types in java [duplicate]

This question already has answers here:
Does Java guarantee that Object.getClass() == Object.getClass()?
(4 answers)
Closed 5 years ago.
Should I test equality between two class type objects using the == operator or using a more reliable way like Object.equals(Object)
Example
String.class == obj.getClass() or String.class.equals(obj.getClass())
PS: I'm only interested in using class type comparison (not using the instanceof operator)
No, as long as you don't have different classloaders in the JVM.
Each object in java has a corresponding java.lang.Class object and its loaded into JVM once regardless the number of actual instances of the object.
Both versions are basically equal since java.lang.Class uses the standard implementation inside Object:
public boolean equals(Object obj) {
return (this == obj);
}
And since Class is final you can't override that.
Note, however, that once you're working with different classloaders you might get two classes that are basically the same but different instances, i.e. java.lang.String != java.lang.String if both come from different classloaders (that particular example probably won't happen, it's just an illustration).
As a final note, you might want to use equals() anyways if the instance you're calling it on can never be null (and String.class won't be null). That way you're reinforcing the habit to use equals() over == and in the extremely unlikely case that Class will change its implementation of equals() at some point it's probably safer to use it right now.

JUnit assertEquals() not working when comparing two objects

I'm trying to get the hang of Java. Unit testing is pretty important to me and so recently I've started to use JUnit. It was tough to begin with but I'm getting the hang of it. All of my tests have worked up to this point, with the exception of comparing two objects of the same class (I haven't tried testing a function that creates an object of a different class). Basically, when I have a method within a class that creates a new instance of the class, and I try to test the method, I get a weird error.
"expected:runnersLog.MTLog#433c675d but was runnersLog.MTLog#3f91beef"
I have tried researching this problem, but haven't found anything of much help. Here's the link to my classes on github. The method I am trying to test is the mt() method, and the test class is ILogTest.
This is not the only case where I am having this problem. With any class that has a method that returns a new object of the same class, I am getting this exact same 3f91beef error (even when the object is more complicated - with arguments)
assertEquals will use Object#equals for each object being compared. Looks like your class ILogTest doesn't override equals method, so calling Object#equals will just compare the references by itself, and since they're different object references, the result will be false.
You have two options:
Override public boolean equals(Object o) in ILogTest.
Use assertEquals on the relevant fields that implement equals method e.g. String, Integer, Long, etc. This one requires more code but is useful when you cannot modify the class(es) being asserted.
You need to overrride equals, the equals method in the superclass Object checks for references if both references point to the same object equals is true if not false, so you need to write down an equals method that will check your objects content and check if the values are the same, it is also recommended that you override your hashCode method too.
An example could be:
Custom a= new Custom("");
Custom b= a;
//b would be equal a. because they reference the same object.
Custom c= new Custom("");
//c would not be equal to a, although the value is the same.
to learn more you could check:
Why do I need to override the equals and hashCode methods in Java?
If you are using a modern IDE for development (like Eclipse, IntelliJ etc), they can generate these methods for you. Check that out for two reasons: 1) to save time 2) To prevent possible bugs.
In eclipse IDE, you can do so by selecting source -> generate hashCode() and equals().
One more thing, when you implement of of these two, you have to implement the other one as well.

Override equals and cast object to string

EDIT: the question is why cant I use ".contains" (override .equals() in the object) to compare object attributes (a string) instead of comparing the object itself.
Thanks JB:
Turns out I was confusing overriding compareTo() with overriding equals()
EDIT:
QUESTION REDEFINED:
Why cant I override equals to compare strings in my object:
public boolean equals(Object obj){
...
if(obj instanceof String){
String testString = (String) obj;
...
}
...
}
Or even overload for that matter:
public boolean equals(String stringObj){
...
}
I read somewhere that the compiler doesn't use logic to decide this, it uses types. So if I then call myObj.equals(stringOne + "_" + stringTwo) shouldn't this work as it knows a string is being passed?
Thanks,
Steve.
Why this code doesn't make sense:
because Comparable is supposed to respect rules: if a < b is true, then b > a must be true. You can compare an instance of your class with String, but a String can't compare with an instance of your custom class. You're thus breaking the contract of Comparable
because Vector doesn't use compareTo() to check if an element exists or not. It uses equals().
Because you shouldn't alter the nature of a class just to implement a specific use-case consisting in adding instances of this class to a list and check for duplicates. This logic should be outside of the class. You could simply loop through the list and check is an instance with the item and position already exists or not, before creating your custom class instance.
because you shouldn't use Vector for many years (since Java 2 - we're at Java 8). And since it seems the goal is to avoid duplicates, what you should use is a Set.
Do the right thing, and use a HashSet. Make sure CustomClass implements equals() and hashCode() correctly. You could also use a HashMap<CustomClassKey, CustomClass>, where CustomClassKey is a simple class containing the two fields identifying your CustomClass instances.

Categories