Vector concept
Hi ALL
I have a stupid question!please help me to make it clear.
Vector vec =new Vector();
vec.addElement(new myObject(1,2));
....
myObject otherone =new myObject(1,2);
if(! vec.contains(otherone))
vec.addElement(otherone);
.....
class myObject{
int i;
int k;
myObject(int ii,int kk){
i =ii;
k =kk;
}
publicboolean equals(myObject obj){
if(i != obj.getI())returnfalse;
return k==obj.getK();
}
}
The question is on the line
if(! vec.contains(otherone))
I remeber that it compare content, not reference. so It should return true.
and do not add otherone instance, Is it right?
Thanks
> I have a stupid question!please help me to make it
> clear.
Stupid enough [Just joking! :P ]
> The question is on the line
>
> if(! vec.contains(otherone))
>
> I remeber that it compare content, not reference. so
> It should return true.
No, the comparison is not based on the content exactly. The contains() method, as per the API documentation, returns true if and only if the specified object is the same as a component in this vector, as determined by the equals method; false otherwise.
> nd do not add otherone instance, Is it right?
That would depend on how the equals() method determines the equality of your objects.
> I remeber that it compare content, not reference. so
> It should return true.
If you override the equals method, then it does whatever your equals implementation tells it to do. (The usual way to do this would be to compare some or all of the fields--the "contents"--of the two objects.)
If you do not override equals, then it compares references, exaclty like ==.
See here for how to override equals:
http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf
jverda at 2007-7-14 21:40:00 >

Try using statements:
System.out.println(vec); //right after vec.addElement(new myObject(1,2));
&
System.out.println(otherone); // after myObject otherone = new myObject(1,2);
You will see two different values in the console. That is,
if(! vec.contains(otherone))
is comparing the values of VECTOR viz. two Objects & not actually the values in those objects.. As, the two objects are using two different areas in memory hence, you are getting a false from the IF condition.
Note that you are not overriding the equals() method of Object in your example class:
public boolean equals(Object obj){
if (obj == null || !(obj instanceof MyObject)) {
return false;
} else {
return this.i == ((MyObject) obj).i && this.k == ((MyObject) obj).k;
}
}
You must not change the type of the parameter. If you do, you'll be overloading and not overriding.
Please don't use instanceof in an equals() method - you will break the general contract of equals() if you ever subclass this class.
> Please don't use instanceof in an
> equals() method - you will break the general
> contract of equals() if you ever subclass this
> class.
That depends on the contract. If you want different subclasses to be equal to each other, you must use instanceof.
jverda at 2007-7-14 21:40:01 >

Hehe! Didn't we just have this conversation elsewhere?! :-) I think you know full well that you can only get away with this if you are in charge of the whole hierarchy and every leaf is final!
> :-) I think you know full well that you
> can only get away with this if you are in charge of
> the whole hierarchy and every leaf is final!
Not at all. You just have to document it in the parent class or interface, and every implementor is responsible for honoring that contract.
jverda at 2007-7-14 21:40:01 >

OK, I see I'm going to have to give a concrete example...
Let's say I have...
Object < Animal < Mammal < Cat
I can't imagine my hierarchy going any further, so I write:
public class Cat extends Mammal {
// ...
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof Cat)) return false;
Cat that = (Cat)obj;
// .. compare contents of this and that
}
}
All is well and good. I can compare cats to other cats, etc.
Now, let's say someone else comes along and creates Lion which follows the same pattern (specifically, using obj instanceof Lion). Now, if I create a cat, and a separate lion (having the same major attributes as the cat I created) then:
cat.equals(lion); // will be true, whereas
lion.equals(cat); // will not, since cat is not an instanceof Lion
We have broken the contract of equals(); specifically, it is no longer symmetric (I think I said reflexive earlier, or in another post).
Why is this a problem? Perhaps it isn't for you. But imagine that you've been good and done interface-based programming and you're passed a list. This list has cats in it. (In Java 5, it might even be a List<Cat>). Now, you want to test and see if the list contains a given lion, so you say:
if (listOfCats.contains(lion)) ...
What happens if you develop this code using a list which iterates over its contents and checks if item_in_list.equals(item_to_search_for), and at some later stage you swap your list implementation for one which does item_to_search_for.equals(item_in_list). All of a sudden your compare fails.
This argument holds for any user of equals() - Set, Map, etc.
> OK, I see I'm going to have to give a concrete
> example...
Not for my benefit. It's the same as what I said in the other thread.
If you want instances of different subclasses to be able to be equal to each other, you have to use instanceof the parent class or interface. Again, I direct you to Set, List, Map. Any List can be equal to any other List. ArrayList, LinkedList and any other implementation have to do instanceof List in order to honor the contract.
Lion would not do instanceof Lion. It would do instanceof Cat, assuming you wanted any Cat or sub-Cat to be able to be equal to any other. That doesn't really make sense here--I wouldn't expect a housecat to be equal to a cougar--but that's not the point.
jverda at 2007-7-14 21:40:01 >

>> if (obj == null || !(obj instanceof MyObject)) {
Note that the null check here is not needed - null is not instanceof anything.
On the whole equals and instanceof discussion: I fail to see how you could write any equals method that compares instance fields without instanceof. I mean, you would need to cast the method argument to do so, right?
> On the whole equals and instanceof discussion: I fail
> to see how you could write any equals method that
> compares instance fields without instanceof. I mean,
> you would need to cast the method argument to do so,
> right?
You need some test if the two objects are of the same type, else you could get ClassCastException. The two options we're talking about are instanceof and getClass. Each is appropriate in some situations. Instanceo is for when you want a whole subtree to be able to be equal to each other--for example a HashSet, a LinkedHashSet, and a TreeSet could all be equal. GetClass is for when you require the two objects to be exactly the same class.
jverda at 2007-7-14 21:40:01 >

Thanks for explaining the difference between getClass () and instanceof :|Anyway, do you have a link to where I can read the previous discussion that was mentioned? I've been searching a little, but couldn't find anything. And I don't want to hijack this thread.
If you mean the previous discussion that I mentioned, it was less detailed that what we now have here and won't add anything.
fyi, the getClass() thing looks like this:
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (obj.getClass() != MyClass.class) return false;
MyClass that = (MyClass)obj; // known to succeed due to earlier check
// ... compare contents of this and that ...
}
Yeah, I got that. That would never work with dynamic proxies (I mean the cglib type, not the interfaces variant).About your cat/lion example not equalling symetrically - the question remains whose fault that is, Cat or Lion. I mean, you could override equals in Lion, no?
In this case, it's the fault of Cat. Because it uses instanceof it will accept any subclass. To obey the equals() contract, all subclasses must then also do instanceof. But I've shown how that's broken. Unless they do instanceof Cat, which, as jverd pointed out, would allow a Lion to potentially be equal to a HouseCat which makes little sense.
Worse still, what if Mammal was also using instanceof. In that case, a Mammal could equal a Lion. Now, Lion has to do instanceof Mammal to maintain the contract. But a Lion is surely not equal to an Elephant just because it has the same number of legs.
And all of this pre-supposes that the writer of Lion has knowledge of the workings of the superclasses, which he may not have if they're part of a third-party library. So now, we are extending superclass which break the contract of equals() in ways which we don't know enough about to take a stab at fixing.
And... does it even make sense for a superclass-subclass equality to ever return true? Occassionally, yes. And jverd provides a good example of the Collections Framework (in the other thread). But in general, I would say no.
They way to ensure that you don't trip up unsuspecting extenders when you don't know everything there possibly is to know about a class hierarchy (which, by definition, means that all leaf classes are final - although this doesn't prevent people extending non-leaf classes) is to not use instanceof.
Of course, there's a whole other argument about the brittleness of extension, and one about externalising equality just like comparisons can be externalised via Comparator, but they are, ipso facto, whole other arguments.
> In this case, it's the fault of Cat. Because it uses
> instanceof it will accept any subclass. To
> obey the equals() contract, all subclasses
> must then also do instanceof. But I've shown
> how that's broken. Unless they do instanceof
> Cat, which, as jverd pointed out, would allow a
> Lion to potentially be equal to a HouseCat which
> makes little sense.
That just means this example isn't a good demonstration of when instanceof is useful. It doesn't show that instanceof isn't correct in some cases.
> Worse still, what if Mammal was also using
> instanceof. In that case, a Mammal could equal
> a Lion. Now, Lion has to do instanceof Mammal
> to maintain the contract. But a Lion is surely not
> equal to an Elephant just because it has the same
> number of legs.
Again, not a good example.
> And all of this pre-supposes that the writer of Lion
> has knowledge of the workings of the superclasses,
> which he may not have if they're part of a
> third-party library. So now, we are extending
> superclass which break the contract of
> equals() in ways which we don't know enough
> about to take a stab at fixing.
This is not a problem. If you're extending a class or implementing an interface, you have acces to its docs. Those docs should spell out the equals contract sufficiently for you to know what to do (as, for example, List's do--though it might be nice if they were a bit more explicit).
> They way to ensure that you don't trip up
> unsuspecting extenders when you don't know everything
> there possibly is to know about a class hierarchy
> (which, by definition, means that all leaf classes
> are final - although this doesn't prevent people
> extending non-leaf classes) is to not use
> instanceof.
Again, you don't need to know "everything"--only the equals contracts of your superclasses/superinterfaces.
jverda at 2007-7-21 10:16:35 >

Symmetry is easy to resolve. What's hard to solve is transitivity.
You have two choices. You can make equals final in the base class. This ensures consistent equals but is obviously inflexible. The other way is to (as you suggest) use the concrete type but that's no good if people want their sublcasses to compare.
The real solution to all of this is something that Sun engineers refuse to accept. Take the idea of the Comparator and create an Equalator class.