I was testing my shuffling class and came across one issue I cannot understand. Why does the following assert statement:
assertEquals(new int[]{1}, new int[]{1});
results in an AssertionError? Naturally, the correct answer is "because they are not equal!", but could someone explain me why? And how to test a method, for which I would like the two such objects to be equal?
but could someone explain me why
Sure - arrays don't override equals, therefore they inherit the behaviour from Object, where any two distinct objects are non-equal.
It's even simpler than the version you showed if you use a 0-element array:
System.out.println(new int[0].equals(new int[0])); // false
That's why when checking for equality in non-test code you use Arrays.equals, and when checking for equality in test code you use a dedicated assertXyz method (where the exact method depends on the version of JUnit etc).
assertEquals calls the equals object in one of the objects to compare it with the other.
Arrays need to be compared using Arrays.equals() if you want a full comparison of the two arrays, otherwise unfortunately they just use the Object equals method.
See also: equals vs Arrays.equals in Java
Because you create 2 different objects and they point to different locations in the memory.
When comparing objects, you use the equals() method inherited from the class Object. Now, if you don't override the method in your class, you will have the default behaviour which is the comparison of objects address. In the code you create 2 arrays, but even though their content is the same, not the content is tested for being equal, but the objects reference by using the inherited equals() method from Object class.
Related
How does HashSet1.retainAll(HashSet2); work behind the scenes?
I am adding objects with identical parameters to two different HashSet, but when I use the above I don't seem to get the right result. I.e it doesn't detect it's actually the same parameters in the object.
Is this method above comparing the actual address of my objects in the set?
If so, how can I go about making it compare parameters of the objects instead.
Perhaps override equals?
I have overwritten the hashCode and .equals methods in my class and this has resulted in the method comparing the correct parameter's rather than object address's. Thanks goes to #marstran for his advice on this matter.
This seems like a silly question but why do we override equals method instead of creating a new method with new name and compare using it?
If I didn't override equals that means both == and equals check whether both references are pointed to same memory location?
This seems like a silly question but why do we override equals method instead of creating a new method with new name and compare using it?
Because all standard collections (ArrayList, LinkedList, HashSet, HashMap, ...) use equals when deciding if two objects are equal.
If you invent a new method these collections wouldn't know about it and not work as intended.
The following is very important to understand: If a collection such as ArrayList calls Object.equals this call will, in runtime, resolve to the overridden method. So even though you invent classes that the collections are not aware of, they can still invoke methods, such as equals, on those classes.
If I didn't override equals that means both == and equals check whether both references are pointed to same memory location?
Yes. The implementation of Object.equals just performs a == check.
You override equals if you are using classes that rely on equals, such as HashMap, HashSet, ArrayList etc...
For example, if you store elements of your class in a HashSet, you must override hashCode and equals if you want the uniqueness of elements to be determined not by simple reference equality.
Yes, if you don't override equals, the default equals implementation (as implemented in the Object class) is the same as ==.
In addition to the main reason, already given in other answers, consider program readability.
If you override equals and hashCode anyone reading your code knows what the methods are for. Doing so tells the reader the criteria for value equality between instances of your class. Someone reading your code that uses equals will immediately know you are checking for value equality.
If you use some other name, it will only confuse readers and cost them extra time reading your JavaDocs to find out what your method is for.
Because equals() is a method of the Object class, which is the superclass of all classes, and due to which it is inherently present in every class you write. Hence every collection class or other standard classes use equals() for object comparsion. If you want your custom class objects to be supported for equality by other classes, you have to override equals() only (since other classes know that for object comparion call equals()). If you are only using your own classes, you might create a new method and make sure everything uses your custom method for comparison.
The equals and hashcode method are special methods, widely used across the java's utility classes specially collection framework, and the wrpper classes e.g. String, Integer have overridden this method, So e.g. if you are placing any Object of your choice which has correct equals and hashcode implementation inside the HashSet, to maintain the property of uniqueness the hashcode will compare with all the existing object in hashset, and if it finds any of the hashcode matching then it looks into the equals method to double check if both are really equal and if that equality check also is pass then incoming object is rejected, but if the hashcode equality check is not passed then hashset will not go for the equals method and straight way place that object into the hashset. So we need to make sure the implementation of equals and hashcode is logically proper.
A class like HashMap<T,U> needs to have some means of identifying which item in the collection, if any, should be considered equivalent to a given item. There are two general means via which this can be accomplished:
Requiring that anything to be stored in a collection must include virtual methods to perform such comparison (and preferably provide a quick means (e.g. hashCode()) of assigning partial equivalence classes).
Require that code which creates the collection must supply an object which can accept references to other objects and perform equivalence-related operations upon them.
It would have been possible to omit equals and hashCode() from Object, and have types like HashMap only be usable with key types that implement an equatable interface that includes such members; code which wishes to use collections of references keyed by identity would have to use IdentityHashMap instead. Such a design would not have been unreasonable, but the present design makes it possible for a general-purpose collection-of-collections type which uses HashMap to be usable with things that are compared by value as well as by identity, rather than having to define a separate types for collection-of-HashMap and collection-of-IdentityHashMap.
An alternative design might have been to have a GeneralHashMap type whose constructor requires specifying a comparison function, and have IdentityHashMap and HashMap both derive from that; the latter would constrain its type to equatable and have its identity functions chain to those of the objects contained therein. There would probably have been nothing particularly wrong with that design, but that's not how things were done.
In any case, there needs to be some standard means by which collections can identify items that should be considered equivalent; using virtual equals(Object) and getHashCode() is a way of doing that.
Question 1
There are Two things.
equals() is Located inside Object class
Collection framework using equals() and hashcode() methods when comparing objects
Question 2
Yes for comparing two Object. but when You comparing two String Objects using equals() its only checking the value.
Scheme knows three different equivalence operators: eq?, eqv?, equal?. Sere here for details. In short: eq? tests references, eqv? tests values and equal? recursively tests the values of lists. I would like to write a Java generic which needs the functionality of Scheme´s equal?.
I tried to use Java´s equals() method, because I thought it does a value comparison, because for a reference comparison the == operator exists and there is no need for equals to do the same. But this assumption is completely wrong, because equals in Java is completely unreliable. Sometimes it does a value comparison and sometimes it does a reference comparison. And one can not be sure which class does a reference comparison and which class does a value comparison.
This means that equals can not be used in a generic, because the generic would not do the same for all types. And it is also not possible to restrict the generic type in a way that only types are acceptable which implement the correct value comparison.
So the question is: how to do a reliable value comparison in a generic? Do I have to write it on my own from scratch?
By the way: I think Java´s equal failure does not start with Array. It starts already with Object. I think it is wrong that equals for two objects returns false. It must return true, because if you do a value comparison of something which does not have a value the values can not differ and therefor they must be the same. Scheme does it in that way and it is perfectly reasonable: (equal? (vector) (vector)) -> #t.
In Scheme, list equivalence is based completely on the structure of the items.
In Java by comparison, equality is context-dependent depending on the type of object, and may use some or all of the internal structure in its equivalence calculation. What it means for two objects of the same type to be "equal" is up to the object type to determine, so long as the general contract for equals is met (most notably that it forms an equivalence relation with all other objects).
Assuming all types used in a program have a reasonable equals definition, they should have a "reliable" value comparison, at least in the sense of the object oriented paradigm.
Returning to the analogous Java equal? implementation. It's a bit hard to piece together from the question's phrasing, but from context clues it appears that this is also attempting to operate on lists of items. The equals method on Java's List type already implements behavior directly analogous to Scheme's equals? operation:
Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if Objects.equals(e1, e2).) In other words, two lists are defined to be equal if they contain the same elements in the same order.
This definition also means that recursive list structures also work in a similar manner as Scheme's equals? operation.
Note that the List behavior is notably different from that of Java's array type (which you mention in your question). Arrays in Java are a fairly low-level type, and do not support much of the typical object-oriented functionality one might expect. Of particular note, for equality, arrays are compared by object reference rather than by a structural comparison of the items in the array. There are ways to do sensible equality comparison on arrays using methods in the Arrays class (e.g. Arrays.equals and Arrays.deepEquals).
As an aside, to address your postscript about the equality of two bare Objects.
assert !(new Object().equals(new Object()))
From an object-oriented perspective, it is sensible that two bare objects be equal only if they're the same reference. First, as mentioned above, there is not a direct relation between an object's internal structure and its equality, so there's no need for them to be equal. There is virtually no context as to what two different instances of Object represent from a object modeling perspective, so there's no inherent conceptual way to tell that these two objects are logically the "same" thing.
In summary, assuming all the types in your list have a sensible version of equals() defined per their object's type, Java's List.equals() behaves directly analogously to Scheme's equals? operation.
I've an XML Beans Interface called SynonymsRequest with:
public interface SynonymsRequest extends org.apache.xmlbeans.XmlObject {...}
I want to test two instances of SynonymsRequest for equality:
SynonymsRequest s1 = SynonymsRequest.Factory.newInstance();
s1.setQueryText("blub");
s1.setRequesterId(BigInteger.valueOf(1));
SynonymsRequest s2 = SynonymsRequest.Factory.newInstance();
s2.setQueryText("guck");
s2.setRequesterId(BigInteger.valueOf(1));
I've tried the following:
assertTrue(s1.equals(s2)); => assertion does not pass
assertEquals(0, s1.compareTo(s2)); => throws ClassCastException
assertEquals(0, s1.compareValue(s2)); => assertion does not pass (returns 2, not compareable)
assertTrue(s1.valueEquals(s2)); => always returns true, no matter if the two instances are equal
So what is the proper way of doing this?
If it doesn't impact the performance of your program, you could compare them like this:
assertTrue(s1.xmlText().equals(s2.xmlText()));
Otherwise, I guess you will have to write your own custom comparator.
As I understand, the comparison compares two simple values only. It cannot deduct your desired comparison algorithm.
Or I don't understand what exactly do you mean?
XmlBeans doesn't support a deep comparison so you'll have to write your own. There was a thread on the dev mailing list a while ago about a schema-aware comparison, but I'm not sure anything became of it:
http://www.mail-archive.com/dev#xmlbeans.apache.org/msg01960.html
Noticed this a while back - if the two objects have toString() methods generated when they were made, then you can to an .equals on the toString() methods of the objects. These can be compared with relativ ease, since they will check if the output xml is equivalent.
I have the following situation: I need to sort trees based by height, so I made the Tree's comparable using the height attribute. However, I was also told to overwrite the equals and hashCode methods to avoid unpredictable behaviour.
Still, sometimes I may want to compare the references of the roots or something along those lines using ==. Is that still possible or does the == comparison call the equals method?
equals() is meant to compare an object with rules set by the programmer. In your example you compare your trees by height, so you'll write equals() so it compares heights.
==, as you said, compares references. These aren't touched neither by equals() nor by hashCode(). So you won't change its behaviour.
Yes, == will not call hashCode or equals. You can still test for reference equality like this.
== does not call equals. So it's still find for identity checks.
As many implementations of equals start with this == other check you would get a literal StackOverflow if it were calling equals behind the scenes.
I think that a bigger question here is whether it is appropriate to implement comparable on these objects. It may be more appropriate to use a Comparator for the operations that work on height, and not embed ordinal computation in the class itself.
My general philosophy on this is to only implement Comparable if there is a truly natural ordering for the object. In the case of a tree node, is height the only way that anyone could ever want to sort? Maybe this is a private class, and the answer is 'yes'. But even then, creating a Comparator isn't that much extra work, and it leaves things flexible in case you decide you want to make that tree node a protected or public class some day.
== tests referential equality. It will not call equals.
Overriding the equals() method will have NO effect on the == operator.
== is used to test if 2 references point to the same object.
equals() method "meaningfully" compares 2 objects.
It is important to realize the implication of the work "meaningful" here. Equality is easier to understand when you are comparing, for instance, 2 Strings or 2 integers. This is why, the equals() method - inherited from the Object class - is already overridden by the String and Wrapper classes (Integer, Float, etc). However, what if you are comparing 2 objects of type Song. Here, equality can be established on the basis of
1) Artist name
2) Song name
3) or some other criterion
Therefore, you have to override the equals() method to "explicitly" determine "when" 2 Song objects are considered equal.
The "unpredictable behavior" you mentioned in your question relates to objects like the one above (Song) behave when dealing with Collections like Map. You SHOULD NOT use these objects in a map until you override both the equals() and hashcode() method. The reason being how hashmap search and indexing works. Refer the JavaDoc for the specifc rules. What you should remember is:
If 2 objects are meaningfully equal, their hashcode should return the same value. However, it is not necessary for 2 objects to be equal, if they return the same hashcode. Again, Java doesn't enforce any rules regarding this. It is your responsibility to implement the equals() and hashcode() methods correctly.