Strange behaviour of Assert.assertEquals - java

According to many posts here, Assert.assertEquals should compare collections using deep insight, and two arrays of the same content should be equal.
I have JUnit 4.12 installed.
Calling
List<Integer[]> result, targetResult;
(both are created as ArrayList)
....
Assert.assertEquals("counted small array ", result, targetResult);
, where result and targetResult have the same content, the test fails though.
I have looked how the assertEquals do the job. For comparison of the Integer arrays it reached:
//----in AbstractList:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
...
//and more deep, in Object:
public boolean equals(Object obj) {
return (this == obj);
}
And that means, that it compares simply references.
How can I make Assert.assertEquals() to work correctly?

The problem with assertEquals is the assumption that the equals(Object) is sane. Unfortunately, all arrays inherent from Object directly and have no specialised methods. This means that you have to call Arrays.equals(a, b) to compare two arrays, however if those arrays are inside a collection there is no way to do this conveniently.
Note: I don't know why printing [Ljava.lang.Integer#72173fed is a good toString for such an array either (it is something I have ranted against in my blog more than once)
And that means, that it compares simply hashcodes.
It doesn't compare hashCode()s, it compares references. hashCode()s are not memory addresses, nor can they be as they cannot change when the object is moved in memory.
If you want your data structures to be equal, use a collection which supports equals as you expect
List<List<Integer>> result
if you you want efficiency as int use 4 bytes and Integer can use 20 bytes including it's reference.
List<int[]> result
public static void assertEqualsArray(List<Int[]> a, List<int[]> b) {
// compare the list of arrays.
}

Consider:
Assert.assertArrayEquals(result.toArray(), targetResult.toArray());

Related

Common case for comparing two objects references

Beside checking if null (something == null) when do we use object reference comparisons in Java?
I can't think of any case to use object reference comparisons. For me that seems a little weird for a language abstracting all memory allocations.
Comparing singletons - singleton should has only one instance and could be checked for identity instead of equality.
Comparing enums (enums are singletons)
In some equals methods themselves like in (AbstractList):
public boolean equals(Object o) {
// Checking identity here you can avoid further comparison and improve performance.
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
It's faster than a full equals comparison.
The reasoning is simple, if two objects are the same, they must be equal. Therefore it's often used in equals implementations but also to compare enums as J-Alex already pointed out.
Comparing Object references with == is useful when we need to see if two values refer to the same object.
With object references, the use of == is generally limited to the following:
Checking a reference is null.
Comparing two enum values, because there is only one object for each enum constant.
Checking if two references are to the same object.
In addition, by default, Object#equals() uses only the == operator for comparisons. This method has to be overridden to really be useful:
public boolean equals(Object obj) {
return (this == obj); // Comparing object references by default
}

Java equal method explanation on the following code

I have been reading a book called Thinking in Java on Java(I come from C background). I came across the following two set of codes
public class EqualsMethod {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
}
}
//Output: true
I understand that this equal method is comparing the reference. But n1 and n2 are two object residing in ´two different "bubble" in the heap. So how come they are equal?
Another example code is
class Value {
int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
} /* Output:false
}
Why does this give false? Your in depth answer would be much anticipated. Thank you.
The behavior of equals in your custom classes is entirely up to you. If you override it, you decide when two objects of your class are considered equal to each other. If you don't override it, you get the default implementation of Object class, which checks if both references refer to the same object (i.e. checks if v1==v2 in your example, which is false).
Root of the issue :
You have not overrriden eqauals and hashCode and then JVM assigns a new hashCode to any object you create in the case of Value class
=================
Solution :
You will need to define the criteria on which the identities of the value object is measured i.e do the following
1) Override the equals method and specify that the equality is checked over the value of the instance variable i
2) Override Hashcode and use instance variable i for the hashCode comparison
== is used in the equals method in the object class to avoid unnecessary calculation if the two refrences point to the same object and if not go ahead with the calculation and comparisons
public boolean equals(Object anObject)
{
if (this == anObject) {
return true;
}
else{
// Do the calculation here to check the identity check
}
I understand that this equal method is comparing the reference.
Wrong. In the Object class, this method contains a referential comparison, but Integer has it's own implementation, which overrides the one provided by Object.
It compares the values of the two Integers, not their references.
Integer is valuable type. So comparing to Integer variables performing by comparing their values. Which are equal in your particular case.
Comparing two objects (reference type) performing by comparing the references, which are not equal.
You could write your own comparison logic by overloading the equals() method in your class.
Integer has the method equals() that compare the value, and your Value class doesn't. It makes the Value class with equals compare the "pointer", and they're different.
If you override the method equals in your class Value comparing the attribute i from the class, it would return true.
For example
public boolean equals(Object o){
return (this.i == ((Value) o).i) ? true : false;
}
Equals method in all Wrapper classes is overridden by default in java. That's is why first snippet works.
For your own classes, you have to provide an implementation of equals method.
By default the equal method in Java check if the two Object references are the same. You can #Override the method, and do what you want. So it is normal that you get False, because the two Object are different.
So how come they are equal?
Integer is an Object. On the other side int is a simple type.
Integer's equals() method compare int inside, because it's overriding Object equals() method. int's there has the same value.
Why does this give false?
Your Value class doesn't override equal's method, so then refferences are compared, exactly like when you write v1 == v2. In this case they are different Objects so it's false.
Because you have not override equals method. If you do not override it then it will check if the reference are equal or not and return accordingly.
You can refer equals() method defined in Integer class.
System.out.println(n1.equals(n2)) // this prints true because it refers to Integer equals method.
Similarly you will have to override it for your Value class like.
class Value {
int i;
#Override
public boolean equals(Object obj) {
boolean returnValue = false;
if (obj != null && obj instanceof Value) {
Value valObj = (Value) obj;
if (this.i == valObj.i) {
returnValue = true;
}
}
return returnValue;
}
}
Now System.out.println(v1.equals(v2)); prints true.
Hi your understanding of equals and == is completely wrong or opposite to what it actually is.
equals() method also checks for reference as == does, there is no difference between both of them unless you override the equals method.
== check for reference equality. For better understanding see Object class source code.
public boolean equals(Object obj) {
return (this == obj);
}
Why is it working in your case? is because Integer class overrides the equals method in it.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
n
}
Now when you use your custom class to check equality what it is doing is basically calling.
v1==v2
How it can give you true? They both have different memory locations in heap.
If still things are not clear put break points in your code and run it in debug mode.

How to detect if the List contains itself in Java

From Java documentation:
Note: While it is permissible for lists to contain themselves as elements, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a list.
The problem is that the hash code of a List object is computed recursively.
int hashCode = 1;
for (E e : list)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
The question is how to make my code idiot proof and detect whether a List object (or some of its items or even deeper) contains the List object itself.
How to keep a list of List objects while traversing the List object and be able to call contains()-like method? Is keeping System.identityHashCode(object) and testing against it good enough?
System.identityHashCode will help, but it'll almost certainly be simpler to use one of the built-in tools to track objects by identity -- IdentityHashMap.
boolean containsCircularReference(Iterable<?> iterable) {
return containsCircularReference(
iterable,
Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>()));
}
private boolean containsCircularReference(Object o, Set<Object> seen) {
if (seen.contains(o)) {
return true;
}
seen.add(o);
if (o instanceof Iterable) {
for (Object o2 : (Iterable<?>) o) {
if (containsCircularReference(o2, seen)) {
return true;
}
}
}
return false;
}
For reference, you cannot depend on System.identityHashCode being collision-free. For starters, you can allocate more than 2^32 objects in a JVM, and there are only 2^32 distinct identityHashCodes possible...
If it's not just membership in an Iterable, but any circular reference at all, that gets harder, albeit doable with reflection. That said, the existence of that sort of circular reference does not necessarily imply equals and hashCode won't work; circular references are perfectly okay as long as the references in equals and hashCode methods are acyclic, and there's no universal way to detect that.

Java HashSet contains Object

I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal. Now I store some instances of that class in a HashSet so that there are no instances with the same names in the HashSet.
My Question: How is it possible to check if the HashSet contains such an object. .contains() wont work in that case, because it works with the .equals() method. I want to check if it is really the same object.
edit:
package testprogram;
import java.util.HashSet;
import java.util.Set;
public class Example {
private static final Set<Example> set = new HashSet<Example>();
private final String name;
private int example;
public Example(String name, int example) {
this.name = name;
this.example = example;
set.add(this);
}
public boolean isThisInList() {
return set.contains(this);
//will return true if this is just equal to any instance in the list
//but it should not
//it should return true if the object is really in the list
}
public boolean remove() {
return set.remove(this);
}
//Override equals and hashCode
}
Sorry, my english skills are not very well. Please feel free to ask again if you don't understand what I mean.
In your situation, the only way to tell if a particular instance of an object is contained in the HashSet, is to iterate the contents of the HashSet, and compare the object identities ( using the == operator instead of the equals() method).
Something like:
boolean isObjectInSet(Object object, Set<? extends Object> set) {
boolean result = false;
for(Object o : set) {
if(o == object) {
result = true;
break;
}
}
return result;
}
The way to check if objects are the same object is by comparing them with == to see that the object references are equal.
Kind Greetings,
Frank
You will have to override the hashCode method also.
try this..
Considering only one property 'name' of your Objects to maintain uniqueness.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (name == null ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
User other = (User) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal.
This breaks the contract of .equals, and you must never do it no matter how convenient it seems.
Instead, if you want to index and look up elements by a certain attribute such as the name, use a HashMap<Name, YourType> to find them. Alternatively, use a TreeSet and pass it a Comparator that compares the name only. You can then remove the incorrect equals method.
There are then three ways if you want to find objects by reference equality:
Your objects have no inherent or useful notion of equality.
Don't implement equals. Leave it to its default. You can then use a HashSet to look for reference equality, and a HashMap or TreeSet to index them by any specific attributes.
Your objects do have a useful, universal notion of equality, but you want to find equivalent instances efficiently anyways.
This is almost never the case. However, you can use e.g. an Apache IdentityMap.
You don't care about efficiency.
Use a for loop and == every element.
HashSet contains uses the equals method to determine if the object is contained - and duplicates are not kept within the HashSet.
Assuming your equals and hashcode are only using a name field...
HashSet<MyObject> objectSet = new HashSet<MyObject>();
MyObject name1Object = new MyObject("name1");
objectSet.add(new MyObject("name1"));
objectSet.add(name1Object);
objectSet.add(new MyObject("name2"));
//HashSet now contains 2 objects, name1Object and the new name2 object
//HashSets do not hold duplicate objects (name1Object and the new object with name1 would be considered duplicates)
objectSet.contains(new MyObject("name1")) // returns true
objectSet.contains(name1Object) // returns true
objectSet.contains(new MyObject("name2")) // returns true
objectSet.contains(new MyObject("name3")) // returns false
If you wanted to check if the object in the HashSet is the exact object you are comparing you would have to pull it out and compare it directly using ==
for (MyObject o : objectSet)
{
if (o == name1Object)
{
return true;
}
}
If you do this alot for specific objects it might be easier to use a HashMap so you don't have to iterate through the list to grab a specific named Object. May be worth looking into for you because then you could do something like this:
(objectMap.get("name") == myNameObject) // with a HashMap<String, MyNameObject> where "name" is the key string.

Finding same objects in Java

I produce a bunch of objects in Java. Each object has attribute area and a set of integers. I want to store those objects for example in a map(keys should be integers in a growing order). Two objects are the same if their area is equal and their sets are the same.
If two objects don't have the same area then there is no need for me to check whether their sets are the same.
What is the best practice for implementing this in Java? How should I compose hash and equal functions?
Here's sample pair of hashCode\equals generated by IDE:
class Sample {
final int area;
final Set<Integer> someData;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Sample sample = (Sample) o;
if (area != sample.area) return false;
if (!someData.equals(sample.someData)) return false;
return true;
}
#Override
public int hashCode() {
int result = area;
result = 31 * result + someData.hashCode();
return result;
}
}
This code assumes someData can't be null -- to simplify things. You can see that equality of types is checked at first, then area equality is checked and then equality of Set<Integer> is checked. Note that built-in equals of Set is used in this -- so you have re-usage of that method. This is idiomatic way to test compound types for equality.
You just need your object to implement the Comparable interface and code your logic in the compareTo method. Here's a good link to help you achieve that.
A rule of thumb is that you should compare all relevant fields in your equals() implementation (fastest first, so compare your areas up front, then the integer sets) and use THE SAME fields in your hashCode(). If in doubt, use Eclipse's Source - Generate hashCode() and equals()... feature (and then fix the equals() code to compare the areas first.)
Just compare their area first in equals (after the == and type check of course), and return false if these differ. If the areas equal, go on and compare the sets.
For implementing equals (and hashCode) in general, here is a relevant thread and a good article (including several further references).

Categories

Resources