What is the difference between Arrays and ArrayLists equality - java

I am reading Oracle Java Certification book. I'm finding following sentences hard to grasp.
Two arrays with the same content are not equal but ArrayLists equal.
And If you call remove(0) using an empty ArrayList object, it will
compile successfully :/
What does it mean ? Wonder why and how ? Can anyone explain it ?

because equals on arrays test for reference equality, wether or not the two variables are actually references to the same object. See https://stackoverflow.com/a/8777279/2442804 ArrayList implements it differently and checks its contents
Why should it not? It is just some method call one some object that is not allowed at runtime. But that is nothing the compiler is supposed to check - period. The call compiles fine, but at runtime the code detects that you are not allowed to call that method in the given situation.

Related

At which point array class is being created in java?

Today I tried to compare two arrays using equals(), it obviously failed, I started diggin' etc etc, and after some research I can't quite figure out: at which point in time the class for an array is being created? Cuz I know that int [] a leads to creation of an array class for integers. Who creates it? Why it was impossible to override Object.equals() so that it doesn't compare two objects and compares elements of arrays instead? Would be very grateful if someone could explain or provide a link, which would help to understand that.
Array doesn't override equals() of the Object class.
So it will not use the equals() method of the objects that it holds when equals() is invoked on an Array.
If you want to compare two arrays of integer, you can use Arrays.equals() method.
If it doesn't suit you, create your own method to compare two array of integers.
But overriding equals() of Array is not possible as the class is final and besides it seems rather a weird approach.

How does HashSet1.retainAll(HashSet2); work behind the scenes?

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.

fj.data.Set comparison

In java.util, we can use the containsAll method to compare two java.util.Set. What's the best way to compare two fj.data.Set?
Is there really any "valuable" benefit of using fj over java.util?
I have never used that library nor will I ever, but looking through the API I found the method
public final boolean subsetOf(Set<A> s)
Returns true if this set is a subset of the given set.
Parameters: s - A set which is a superset of this set if this method returns true.
Returns: true if this set is a subset of the given set.
I believe this should be used like a "reversed" containsAll:
a.containsAll(b) is true i.f.f. b.subsetOf(a) is true (not sure how equal sets are handled, my guess is that it's fine).
Afterthought: I just noticed how fishy the wording in the javadoc is. The parameter description is dependent on the output: a superset of this set if this method returns true. You're not supposed to assume on the parameter or use a conditional for it. A better wording would be along the lines of: a set to be checked for being a superset.
To compare two sets use Set.subsetOf. So s1.subsetOf(s2) if s1 is a subset of s2 (in contains terms, s2 contains s1).
To create sets use Set.set which takes an ordering of elements (that is, how to know whether an item is less than another so the set can be stored in a red-black tree).
FunctionalJava uses the functional programming (FP) approach - data is immutable. That makes the Collection interface inappropriate for implementing. Note all the mutation and updating of objects in the Collection interface in methods like add, addAll, remove, etc.
There should be better support for converting to and from java.util.Set, but to convert a fj.data.Set to a java.util class, call set.toStream().toCollection() or set.toList().toJavaList().

Why assertEquals(new int[]{1}, new int[]{1}) results in failure?

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.

How to test for equivalence in a generic class?

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.

Categories

Resources