I have a base class for multiple data object types in Java. I want to create an equals method in the base class, that works directly when inherited.
Equality is determined by the two objects
belonging to subclasses of the base class. This is easily achievable using
if (!(anObject instanceof BaseClass))
return false;
having the same ID. The ID field is defined by the base class so we can here test that.
if (this.id != ((BaseClass) anObject).id)
return false;
belonging to the same class. This is where I have the problem. Two objects may be of different types (and so be in different lists), but have the same ID. I have to be able to distinguish them. How can I do this?
Use
this.getClass() == anotherObject.getClass()
instead of instanceof. This will return true only if the two object belong to the same class (it's safe to check if class objects are equal by reference). And after that you may compare the id.
You should read this article for problems when implementing equals.
To make it short: use this.getClass()==other.getClass() instead of instanceof, because otherwise the equals() relationship will not be transitive (superInstance.equals(subInstance) will be true, but subInstance.equals(superInstance) will be false).
If I understand you question correctly, you need a way to differentiate two objects of same Class with same id. If so, for this you may use toString() which gives unique representation of objects unless they are string objects. Of course, you must not have overridden toString() in your base class.
example:You can use this, only for the third case that you mentioned.
if (this.toString()!= anObject.toString())
return false;
You can do that with Class.isInstance() method. In your base class, do this.
public static boolean isAnInstance(Object obj)
{
return BaseClass.class.isInstance(obj);
}
Then you can check
if (BaseClass.isAnInstance(object))
{
// Class of object is 'BaseClass' or
// it extends the 'BaseClass'
}
Hope this helps.
The best practice to know objects equality is to override hashcode() and equals() if you maitain objects in a collection
you can refer Why do we have to override the equals() method in Java?
Related
I want to compare the super classes of two different objects.If it is same then it should ask for another opponnet. Unless it selects the type that is diffenret. I have the following code for it. But it always returns true.
boolean equal(Characters C)
{
return (C.getClass().getSuperclass()== Char.getClass().getSuperclass());
}
we can compare the objects of different classes by calling O1.getClass()==O2.getClass() function of object if the object has same class it return true else false. In case of inheritance if we want to know that the two objects are belonging to same superclass or different then we calling O1.getClass().getSuperClass()==O2.getClass().getSuperClass() to campare.
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.
So this is from Head First Java (page 563)
The default behaviour of hashCode() is to generate a unique integer
for each object on the heap. So if you don’t override hashCode() in a
class, no two objects of that type can EVER be considered equal.
But a simple Test will disprove this I think.
public class Song {
private String name;
public Song(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object obj) {
Song objectSong = (Song) obj;
return this.getName().equals(objectSong.getName());
}
}
Well this will return true:
Song songA = new Song("A","B");
Song songB = new Song("A","C");
System.out.println(songA.equals(songB));
Am I missing something? What is it that the book is trying to tell me?
The default behaviour of hashCode() is to generate a unique integer
for each object on the heap. So if you don’t override hashCode() in a
class, no two objects of that type can EVER be considered equal.
You're misinterpreting. The author isn't saying that a method (that's all equals and hashCode are) can't return true for two different objects. They're saying that semantically two objects should not be considered equal if the result of their hashCode isn't equal. They are describing how hashCode should be used. If you use it differently, you may get weird and unexpected results.
You need to override hashcode so that the class behaves as expected with hashcode based collections (and anything else).
For example what happens if you put your song in a HashSet, and then try to put another one in ?
You should always override Hashcode if you override equals, and vice versa. Make sure they are consistent.
(josh bloch effective java, is a good starting point)
In Java, every object has access to the equals() method because it is
inherited from the Object class. However, this default implementation
just simply compares the memory addresses of the objects. You can
override the default implementation of the equals() method defined in
java.lang.Object. If you override the equals(), you MUST also override
hashCode(). Otherwise a violation of the general contract for
Object.hashCode will occur, which can have unexpected repercussions
when your class is in conjunction with all hash-based collections.
Source: http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20 (take a look at it, it has good examples).
Conclusion: you only need to override equals for a simple comparison. However, you SHOULD also override hashCode for other aspects, such as hash based collections.
I am creating the method .equals(Die aDie) in my program. Do I compare every instance variable including static ones?
boolean equals(Die aDie)
is wrong, classes will call the equals(Object) method and ignore your equals(Die). Also implement the int hashCode() method using the same fields that equals(Object) uses.
#Override public boolean equals(Object aDie){
if(aDie == null || aDie.getClass() != Die.class)return false;
if(aDie == this)return true;
Die other = (Die)aDie;
...
}
#Override public int hashCode(){
...
}
You can ignore static fields since they are the same for every Die.
Static variables, by definition, are not instance variables, and will therefore always be equal across all instances of the same class.
Definitely not the static ones.
Whether you compare all the instance variables depends on what determines the "identity" of your objects, i.e. when do you consider them equal? This can only be decided in the context of your particular application - we'd need more information.
For example, if you had a class representing books, you might only compare the ISBN number to determine whether two books are the same book, if you just wanted to store metadata about them (title, author). If you merged two such databases, you'd want to eliminate duplicate records.
BUT, if you were implementing a library catalogue of actual physical books, each individual copy is important and different, so you might compare ISBN and copy number. If you merged two libraries, you'd expect to be able to detect duplicate copies.
You would compare every instance variable.
Static variables are guaranteed to be equal, as they are class-specific, not instance-specific, so you don't have to worry about comparing them.
It would make no sense, both because with equals() you compare instances and because, well, they are static: what would you compare them to, themselves?
It is useless to compare static data, as it is shared among all instances of your Die class. But you can compare the various fields by accessing them directly (see example below). Note that if your Die object has complex fields (such as instances of Map, Set, etc), you should also call the equals methods on those objects (again, see example below).
If you want to provide an equals () method, you should override the one provided in the Object class (equals (Object anOtherObject), rather than overloading it, or at least make sure you also override equals (Object anOtherObject) to make sure that it returns the correct value too (the default implementation only checks if it's the same instance). And in your method you should then check if anOtherObject is an instance of Die.
Here's an example, assuming that your Die class has 3 fields: String name, int value and Map<Integer> complexField:
public boolean equals (Object anOtherObject) {
if (anOtherObject == this) {
return true;
}
if (!anOtherObject instanceof Die) {
return false;
}
Die otherDie = (Die) anOtherObject;
if (this.value != otherDie.value ||
!this.name.equals (otherDie.name) ||
!this.complexField.equals (otherDie.complexField)) {
return false;
}
return true;
}
Josh Bloch's "Effective Java" has a very details section on how to correctly implement equals. You should definitely read it.
When a variable is declared with the keyword “static”, its called a “class variable”. All instances share the same copy of the variable (always be equal across all instances of the same class). A class variable can be accessed directly with the class, without the need to create a instance.
I'm using Eclipse to generate .equals() and .hashCode(), and there is an option labeled "Use 'instanceof' to compare types". The default is for this option to be unchecked and use .getClass() to compare types. Is there any reason I should prefer .getClass() over instanceof?
Without using instanceof:
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Using instanceof:
if (obj == null)
return false;
if (!(obj instanceof MyClass))
return false;
I usually check the instanceof option, and then go in and remove the "if (obj == null)" check. (It is redundant since null objects will always fail instanceof.) Is there any reason that's a bad idea?
Josh Bloch favors your approach:
The reason that I favor the instanceof approach is that when you use the getClass approach, you have the restriction that objects are only equal to other objects of the same class, the same run time type. If you extend a class and add a couple of innocuous methods to it, then check to see whether some object of the subclass is equal to an object of the super class, even if the objects are equal in all important aspects, you will get the surprising answer that they aren't equal. In fact, this violates a strict interpretation of the Liskov substitution principle, and can lead to very surprising behavior. In Java, it's particularly important because most of the collections (HashTable, etc.) are based on the equals method. If you put a member of the super class in a hash table as the key and then look it up using a subclass instance, you won't find it, because they are not equal.
See also this SO answer.
Effective Java chapter 3 also covers this.
If you use instanceof, making your equals implementation final will preserve the symmetry contract of the method: x.equals(y) == y.equals(x). If final seems restrictive, carefully examine your notion of object equivalence to make sure that your overriding implementations fully maintain the contract established by the Object class.
What I'm trying to get at here is that if you believe getClass() is the only reliable way to preserve symmetry, you are probably using equals() the wrong way.
Sure, it's easy to use getClass() to preserve the symmetry required of equals(), but only because x.equals(y) and y.equals(x) are always false. Liskov substitutability would encourage you to find a symmetry-preserving implementation that can yield true when it makes sense. If a subclass has a radically different notion of equality, is it really a subclass?
The reason to use getClass is to ensure the symmetric property of the equals contract. From equals' JavaDocs:
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.
By using instanceof, it's possible to not be symmetric. Consider the example:
Dog extends Animal.
Animal's equals does an instanceof check of Animal.
Dog's equals does an instanceof check of Dog.
Give Animal a and Dog d (with other fields the same):
a.equals(d) --> true
d.equals(a) --> false
This violates the symmetric property.
To strictly follow equal's contract, symmetry must be ensured, and thus the class needs to be the same.
Angelika Langers Secrets of equals gets into that with a long and detailed discussion for a few common and well-known examples, including by Josh Bloch and Barbara Liskov, discovering a couple of problems in most of them. She also gets into the instanceof vs getClass. Some quote from it
Conclusions
Having dissected the four arbitrarily chosen examples of implementations of equals() , what do we conclude?
First of all: there are two substantially different ways of performing the check for type match in an implementation of equals() . A class can allow mixed-type comparison between super- and subclass objects by means of the instanceof operator, or a class can treat objects of different type as non-equal by means of the getClass() test. The examples above illustrated nicely that implementations of equals() using getClass() are generally more robust than those implementations using instanceof .
The instanceof test is correct only for final classes or if at least method equals() is final in a superclass. The latter essentially implies that no subclass must extend the superclass's state, but can only add functionality or fields that are irrelevant for the object's state and behavior, such as transient or static fields.
Implementations using the getClass() test on the other hand always comply to the equals() contract; they are correct and robust. They are, however, semantically very different from implementations that use the instanceof test. Implementations using getClass() do not allow comparison of sub- with superclass objects, not even when the subclass does not add any fields and would not even want to override equals() . Such a "trivial" class extension would for instance be the addition of a debug-print method in a subclass defined for exactly this "trivial" purpose. If the superclass prohibits mixed-type comparison via the getClass() check, then the trivial extension would not be comparable to its superclass. Whether or not this is a problem fully depends on the semantics of the class and the purpose of the extension.
This is something of a religious debate. Both approaches have their problems.
Use instanceof and you can never add significant members to subclasses.
Use getClass and you violate the Liskov substitution principle.
Bloch has another relevant piece of advice in Effective Java Second Edition:
Item 17: Design and document for inheritance or prohibit it
Correct me if I am wrong, but getClass() will be useful when you want to make sure your instance is NOT a subclass of the class you are comparing with. If you use instanceof in that situation you can NOT know that because:
class A { }
class B extends A { }
Object oA = new A();
Object oB = new B();
oA instanceof A => true
oA instanceof B => false
oB instanceof A => true // <================ HERE
oB instanceof B => true
oA.getClass().equals(A.class) => true
oA.getClass().equals(B.class) => false
oB.getClass().equals(A.class) => false // <===============HERE
oB.getClass().equals(B.class) => true
If you want to ensure only that class will match then use getClass() ==. If you want to match subclasses then instanceof is needed.
Also, instanceof will not match against a null but is safe to compare against a null. So you don't have to null check it.
if ( ! (obj instanceof MyClass) ) { return false; }
It depends if you consider if a subclass of a given class is equals to its parent.
class LastName
{
(...)
}
class FamilyName
extends LastName
{
(..)
}
here I would use 'instanceof', because I want a LastName to be compared to FamilyName
class Organism
{
}
class Gorilla extends Organism
{
}
here I would use 'getClass', because the class already says that the two instances are not equivalent.
instanceof works for instences of the same class or its subclasses
You can use it to test if an object is an instance of a class, an instance of a subclass, or an instance of a class that implements a particular interface.
ArryaList and RoleList are both instanceof List
While
getClass() == o.getClass() will be true only if both objects ( this and o ) belongs to exactly the same class.
So depending on what you need to compare you could use one or the other.
If your logic is: "One objects is equals to other only if they are both the same class" you should go for the "equals", which I think is most of the cases.
Both methods have their problems.
If the subclass changes the identity, then you need to compare their actual classes. Otherwise, you violate the symmetric property. For instance, different types of Persons should not be considered equivalent, even if they have the same name.
However, some subclasses don't change identity and these need to use instanceof. For instance, if we have a bunch of immutable Shape objects, then a Rectangle with length and width of 1 should be equal to the unit Square.
In practice, I think the former case is more likely to be true. Usually, subclassing is a fundamental part of your identity and being exactly like your parent except you can do one little thing does not make you equal.
Actually instanceof check where an object belongs to some hierarchy or not. ex: Car object belongs to Vehical class. So "new Car() instance of Vehical" returns true. And "new Car().getClass().equals(Vehical.class)" return false, though Car object belongs to Vehical class but it's categorized as a separate type.