• Post Reply Bookmark Topic Watch Topic
  • New Topic

how to use instanceof?  RSS feed

 
Gajendra Kangokar
Ranch Hand
Posts: 94
1
Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi all
in the below code what is instanceof doing/checking?



output is:
a is instance of A
b is instance of B
c is instance of C
c can be cast to A

And what does 'c can be cast to A' mean?

please is there a place where i can know about instanceof operator clearly?

Thanks
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Gajendra Kangokar wrote:hi all
in the below code what is instanceof doing/checking?


For these kinds of "what is X?" questions, it's best to SearchFirst(⇐click). For example, a google search of what is Java isntaanceof should give you plenty of information. After spending some time going through that, if you're still confused, come back with more specific questions about what in particular from those results you had trouble with.

And what does 'c can be cast to A' mean?


It means this is legal:


The (A)c cast tells the compiler to treat the reference variable c as if it had been declared as type A instead of type C. You can find more details from a google search, or in your book or tutorial.

In general, however, instanceof and casting should be avoided. Sometimes they're necessary--or at least much simpler than other alternatives--but often times they're a design smell that tell us we should re-examine our approach.
 
Gajendra Kangokar
Ranch Hand
Posts: 94
1
Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
thanks Jeff,

it is really a very clear explanation.and the next time i will definitely do SearchFirst before posting
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeff Verdegan wrote:In general, however, instanceof ... should be avoided...

@Gajendra: With one major exception: When you're implementing an equals() method; in which case it's my preferred approach - although there are others.

Winston
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Jeff Verdegan wrote:In general, however, instanceof ... should be avoided...

@Gajendra: With one major exception: When you're implementing an equals() method; in which case it's my preferred approach


It goes beyond preference.

Depending on the semantics of your class either instanceof is the correct approach, or getClass() is the correct approach. For cases where different subtypes can be equal to each other (such as the fact that an ArrayList can be equal to a LinkedList), instanceof is the right way to do it. If your design dictates that different subtypes cannot be equal to each other, or if the first level at which you override equals() is a final class, so there can be no descendants, then getClass() is the correct approach.
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeff Verdegan wrote:Depending on the semantics of your class either instanceof is the correct approach, or getClass() is the correct approach. For cases where different subtypes can be equal to each other (such as the fact that an ArrayList can be equal to a LinkedList), instanceof is the right way to do it. If your design dictates that different subtypes cannot be equal to each other, or if the first level at which you override equals() is a final class, so there can be no descendants, then getClass() is the correct approach.

Yes, but what if you don't know? I know that the general rule of thumb is that an equals() method containing instanceof should be final; but suppose I've just created a class that I want to be publically subclassed? It's perfectly reasonable for a subclass to restrict its method to allow only classes of its own type (and if it introduces invariants to the 'equals' process, pretty well mandatory), but why should I "enforce it from above"?

For starters, members of hierarchies that use getClass() are pretty well useless as elements in any kind of Collection, since someone might create one of a supertype, and then wonder why contains() doesn't work the way they expected.

I know this is an old chestnut of an argument, but I'm not yet convinced that getClass() is a proper alternative to instanceof; especially when there's the canEqual() pattern around. They are two fundamentally different approaches; and getClass() just seems too draconian for me (and not Object-Oriented, if you assume that hierarchies are a natural product of OO).

But it's still fun to shoot the breeze.

Winston
 
manish ghildiyal
Ranch Hand
Posts: 136
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
instanceof basically tells whether underlying object referenced by reference variable on LHS of instanceof is of the type provided on RHS of instanceof.

 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
manish ghildiyal wrote:instanceof basically tells whether underlying object referenced by reference variable on LHS of instanceof is of the type provided on RHS of instanceof.

OR a subtype; and that's the important bit. It also returns false if the LHS object is null, which often saves you an extra check.

Winston
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Jeff Verdegan wrote:Depending on the semantics of your class either instanceof is the correct approach, or getClass() is the correct approach. For cases where different subtypes can be equal to each other (such as the fact that an ArrayList can be equal to a LinkedList), instanceof is the right way to do it. If your design dictates that different subtypes cannot be equal to each other, or if the first level at which you override equals() is a final class, so there can be no descendants, then getClass() is the correct approach.

Yes, but what if you don't know?


Then you pick one based on past experience or personal preference or today's horoscope.

I know that the general rule of thumb is that an equals() method containing instanceof should be final;


I wouldn't say that. Rather, the absolute rule for correct behavior is that once a given "level" of the type hierarchy uses instanceof X, then every subclass that provides its own equals must also use instanceof X.

I know this is an old chestnut of an argument, but I'm not yet convinced that getClass() is a proper alternative to instanceof; especially when there's the canEqual() pattern around.


I only looked at canEqual() briefly, but the way I see it, they end up doing the same thing, but canEqual() require less knowledge of the overall hierarchy.

But it's still fun to shoot the breeze.


Indeed! I always enjoy hearing the perspective of the older generations.
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Jeff/Winston,

This is one thread I wanted to understand and I'd be really grateful if one of you could also explain it in little more detailed way.

I have understood the following part of your suggestion.

'For cases where different subtypes can be equal to each other (such as the fact that an ArrayList can be equal to a LinkedList), instanceof is the right way to do it. If your design dictates that different subtypes cannot be equal to each other,' ... getClass() should be used.

I couldn't understand the following parts of your posts.

1. 'if the first level at which you override equals() is a final class, so there can be no descendants, then getClass() is the correct approach'.

2. 'I know that the general rule of thumb is that an equals() method containing instanceof should be final'.

3. 'once a given "level" of the type hierarchy uses instanceof X, then every subclass that provides its own equals must also use instanceof X'.

Basically I haven't understood why a class like MyClass below should not be subclassed.



If you could also explain what could go wrong if MyClass is not final and hence can be subclassed, it'll help me understand your suggestions better.

Thanks :-)


 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Chan Ag wrote:
I couldn't understand the following parts of your posts.

1. 'if the first level at which you override equals() is a final class, so there can be no descendants, then getClass() is the correct approach'.

3. 'once a given "level" of the type hierarchy uses instanceof X, then every subclass that provides its own equals must also use instanceof X'.


One of the rules of equals() is that it should be symmetric. That is, X.equals(Y) should return the same value as Y.equals(X) if X and Y are both non-null.

So, for example, the List interface docs say that any List is equal to any other object that is also a List and that has the same elements in the same order. For this to work--for LinkedList.equals(ArrayList) to give the same result as ArryList.equals(LinkedList), and for it to be true as long as they have the same elements in the same order, both must use instanceof List. They can't use getClass() and they can't use instanceof ArrayList or instanceof LinkedList. Everything from List on down--that is, everything that IS-A List, everything that implements List--must check instanceof List in order to be able to be equal to any other List.

Basically I haven't understood why a class like MyClass below should not be subclassed.


Nobody said it shouldn't be subclassed. But if you do subclass it, and if you override equals, then since MyClass tests for instsanceof MyClass, you have to make sure the subclass also tests instanceof MyClass, not getClass(), and not instanceof SubClass. Otherwise, symmetry will be broken, because MyClass.equals(SubClass) could return true, but SubClass.equals(MyClass) could not.
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OMG... Although I have read about the symmetry rule, I know I couldn't have figured this implication of it. And it's such a big implication :-)

Thanks so much for explaining it with an example.

Greetings and once more, thank you, Jeff.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're very welcome! I'm glad it's clear now.
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeff Verdegan wrote:I wouldn't say that. Rather, the absolute rule for correct behavior is that once a given "level" of the type hierarchy uses instanceof X, then every subclass that provides its own equals must also use instanceof X.

Erm...why?. Assuming that the subclass equals() method is doing its job properly (ie, super.equals(other) && checking its own invariants for its own type), it shouldn't make a bit of difference whether you check for "my type" with instanceof or getClass(). However, once getClass() is involved, you can't then expect any subclass of that branch to work with anything but getClass().
The problem with instanceof is more subtle - viz, unless the superclass method is final, you can violate transitivity (x == y, y == z, but z != x); you won't break symmetry though.

I only looked at canEqual() briefly, but the way I see it, they end up doing the same thing, but canEqual() require less knowledge of the overall hierarchy.

I'd say give it a proper look then, because it's what makes (or can make) instanceof-based equals() methods properly transitive without being final. Unfortunately, you can't force it; but then, you can't force people to implement hashCode() when they implement equals(), can you?

Winston
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Jeff Verdegan wrote:I wouldn't say that. Rather, the absolute rule for correct behavior is that once a given "level" of the type hierarchy uses instanceof X, then every subclass that provides its own equals must also use instanceof X.

Erm...why?.


If Parent does other instanceof Parent, then Parent.equals(Child) can be true. But if Child does not do other instanceof Parent (e.g., it does other instanceof Child or other.getClass() != getClass()), then Child.equals(Parent) can never be true, and symmetry is broken.


I only looked at canEqual() briefly, but the way I see it, they end up doing the same thing, but canEqual() require less knowledge of the overall hierarchy.

I suggest you give it a good look then, because it's what makes (or can make) instanceof-based equals() methods properly transitive without being final.


Yeah, that's the "less knowledge about the overall hierarchy" part I was talking about.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:However, once getClass() is involved, you can't then expect any subclass of that branch to work with anything but getClass().


That's kind of backward, actually. The whole hierarchy from Object down to that getClass() class can be using getClass(), and all is fine--nothing will ever be equal to anything that's not exactly the same class, so symmetry is intact. Below that, once we start using instanceof, subclasses can be equal to other subclasses, but they can't test instanceof the_parent_that_uses_getClass or be equal to that parent class without breaking symmetry. Look at it this way: Object in effect does getClass(), implicitly. Object is fine, and classes below it that do getClass() are fine. But once AbstractList or whatever introduces insanceof List, then all subclasses of AbstractList (actually everything that implements List) has to do instanceof List.

So we start with (effectively) getClass() on Object, and can continue with that until we introduce instanceof. Then we have to stick with instanceof, and it has to be instanceof the same type all the way down.
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeff Verdegan wrote:
Winston Gutkowski wrote:Erm...why?.
If Parent does other instanceof Parent, then Parent.equals(Child) can be true. But if Child does not do other instanceof Parent (e.g., it does other instanceof Child or other.getClass() != getClass()), then Child.equals(Parent) can never be true, and symmetry is broken.

I'm afraid you've got stuck in getClass() mode. The correct way to write a subclass equals() method when you use instanceof is as follows:and, as I said above, it doesn't break symmetry. It can break transitivity though.

Yeah, that's the "less knowledge about the overall hierarchy" part I was talking about.

Give it a look-see. Barbara somebody (very smart German lady). If I find the link, I'll PM it to you.

Winston
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:Give it a look-see. Barbara somebody (very smart German lady). If I find the link, I'll PM it to you.

Angelika Langer maybe? Of Java Generics FAQ fame?

The canEqual() approach seems to come from multiple sources; I read of it from Martin Odersky on Artima.com. But there's a good overview of this and related ideas here.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
I'm afraid you've got stuck in getClass() mode.


No, not stuck at all. Just making it clear that that's what I was talking about as one of the major alternative approaches.

The correct way to write a subclass equals() method when you use instanceof is as follows:and, as I said above, it doesn't break symmetry.


Okay, now I see what you mean. We're not returning false if other instanceof ThisType is false--we just skip the subclass's tests as they don't apply. I was engaged in some sloppy thinking--I assumed "instanceof ThisType" would only be used as "if ! instanceof ThisType return false", but of course this way is valid too. And again, how it's handled depends on the semantics of the class in question. I tend to go right to java.util.List. The above approach could be made to work there, but it would be an unnatural approach.


Yeah, that's the "less knowledge about the overall hierarchy" part I was talking about.

Give it a look-see. Barbara somebody (very smart German lady). If I find the link, I'll PM it to you.


Thanks.
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mike Simmons wrote:Angelika Langer maybe?

That's the chap. Not Barbara at all. Probably thinking of Liskov due to the Alzheimer's.

Thanks for that Mike.

Winston
 
manish ghildiyal
Ranch Hand
Posts: 136
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeff and Winston, thanks a lot guys for this really fantastic discussion.
Would have find it difficult to go to that depth on my own.

Manish
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're welcome.

Between us, Winston and I have mumble mumble years of programming experience, so we've had lots of opportunities to encounter different situations and then talk about them as if we were wise.
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Winston,

Sorry but I still have some questions :-)

I've waited enough for someone else to post them but it seems the rest of the folks have understood things completely. But I haven't and I'm sorry but it's me again who's gonna jump in again and ask some most probably 'stupid' questions ( I couldn't stop myself ). I'm hoping you'd help me understand this.

So far I've understood how an instanceof test that is not coded like you've proposed can break the symmmetry rule that equals' contract requires to be fulfilled.

What I haven't understood is that in the below code, why'd we have a '(other instanceof ThisType)' test if we aren't going to return false after this point? What do you mean when you say 'this class's invariants' ?



When you say that the above code can break the transitivity rule, do you mean that given we have a case as follows and each of the below mentioned class has its own equals as you've proposed, transitivity would be broken because




SuperClass obj.equals(SubClass1 obj) could be true
SubClass1 obj.equals(SubSubClass obj) could be true but
SuperClass obj.equals(SubSubClass obj) could be false?

But why'd SuperClass obj.equals(SubSubClass obj) be false?

Could you please also share with us the code snippet that would be there in the equals method of SubSubClass?

Sorry for intruding into this discussion again .. But I've really waited for someone else to post 'my kind of stupid questions' :-)
I'd appreciate if you could help me understanding things clearly.

Thanks in advance,
Chan
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Chan Ag wrote:What I haven't understood is that in the below code, why'd we have a '(other instanceof ThisType)' test if we aren't going to return false after this point? What do you mean when you say 'this class's invariants' ?

Well, first you need to understand that without something like canEqual(), the whole set-up is fatally flawed; but the idea is this:

If class B extends class A, then class B can be viewed as "A + some stuff", so if you're comparing two class B's, you need to make sure
1. The class A (ie, the superclass) stuff is the same.
2. The "extra stuff" that makes up class B is also the same.

However, if you're comparing an A with a B, or a B with an A, the only stuff you can possibly compare is the "superclass stuff".

The problem comes with the method call:
if you're comparing an A with a B, you'll be calling A.equals(B).
but if you're comparing a B with an A, you'll be calling B.equals(A).
so, assuming you've overridden equals() in B, you'll be calling two different methods.

So, you need to make sure that when you call B's method, you use the superclass (A's) method to compare the "superclass stuff" and only compare the "extra stuff" if you know that 'other' is a B.

Furthermore, even when you call A's method, you still need to be sure that 'other' is an A; otherwise they can't possibly be equal - and, of course, a B is an A because it's a subclass (and instanceof recognises that; getClass() doesn't).

Make sense now?

Reminder: Like I said before, that's the idea, and it does make sure that A.equals(B) will always be the same as B.equals(A) - which is what Jeff and I mean by 'symmetry' - but it doesn't work in practice because it can still violate transitivity; and that's why some very clever people came up with the idea of canEqual(). I suggest you read the docs for Object.equals() for a full explanation of "the rules" because they also explain what 'transitivity' is.

HIH

Winston
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Winston,

Thanks for explaining it with examples. Yeah.. most of it makes sense now. I guess rest of it will start sinking in once I've read the API docs suggested by you.

It seems that all these cases ( as regards just the symmetry enforcement contract) would apply only in cases where
a. we have two or more subclasses of a superclass that overrides equals and has an instanceof test and
b. At least one of these subclasses does not override equals and at least one does and
c. The objects of the subclass that doesn't override equals could meaningfully be equal to other subclasses that override equals.

This could lead to symmetry problem. I tested this with the following code.

If we have, say, an Animal class as follows.



A Dog Subclass as follows..



and a Cat subclass as follows..



and EqualsTest class as follows..


this breaks the symmetry as dog1.equals(cat1) returns false but cat1.equals(dog1) returns true.

This is fine for how often would people want a Dog to equal a Cat and vice versa. If they want them to be not equal always, can't they always have their own equals method in both subclasses. If they want them to be equal always, they could make superclass method final. If they want a combination, they could keep the superclass version non final and provide their own variations of equals in ALL the subclasses.
So symmetry wouldn't be violated in carefully thought about implementations. Would that be correct?

But like Jeff said, Collection interfaces are an exception cause the design allows two different subclasses to be equal. So I understand why we'd need to choose the equals implementation carefully.

Now it seems like most of it is making sense. Thanks to you and Jeff for helping me understand some aspects of something that's a bigger subject than it seems ( to me at least:-) )

However I know.. I have to still read about transitive rules and equals and instanceof implications.

Thanks so much for your help.
Regards,
Chan.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
If class B extends class A, then class B can be viewed as "A + some stuff", so if you're comparing two class B's, you need to make sure
1. The class A (ie, the superclass) stuff is the same.
2. The "extra stuff" that makes up class B is also the same.

However, if you're comparing an A with a B, or a B with an A, the only stuff you can possibly compare is the "superclass stuff".


And here's where you really have to think carefully about your design. I rarely run into this situation in practice. If your B does actually have "extra stuff", you have to think hard about whether it makes sense for "A.equals(A plus extra)" or "B.equals(B minus extra)" to have the possibility of being true. I can't recall the last time it came up for me. Probably 5 years ago at least. Maybe much further back than that.

And it might be that "B.equals(B)" should not be taking into account the extra stuff anyway.

 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeff Verdegan wrote:And it might be that "B.equals(B)" should not be taking into account the extra stuff anyway.

In which case, why are you overriding equals()?

That's the problem with theoretical discussions like these - finding real-life examples that fit.

However, that doesn't mean that there isn't a problem. To me, getClass() is just too facile - every object can only be compared to another one of exactly the same type...ever....even if it's part of a hierarchy.

So you run into a few absurdities, just two of which are:
1. B can possibly be compared with A (with compareTo()), but not equated to it.
2. An anonymous class can never be equal to a regular one (nor indeed, to another anonymous one; even if they're created with the same constructor, with the same values, from the same supertype).

Sounds like a Stalinist design pattern to me: "Keep eet seemple comrades."

And I know: I've just proved Godwin's Law yet again.

Winston
 
Mike Simmons
Ranch Hand
Posts: 3090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stalin, Hitler... well, it was about one those guys, anyway.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Jeff Verdegan wrote:And it might be that "B.equals(B)" should not be taking into account the extra stuff anyway.

In which case, why are you overriding equals()?


Maybe I'm not. But if I am, it's because even though we're not taking extra stuff into account (or maybe there is no extra stuff), there's still something different about B--such as in how it does something. So there may be a more appropriate or efficient way to calculate equals given knowledge of B's internals that B has but A doesn't.

That's the problem with theoretical discussions like these - finding real-life examples that fit.


Amen, brother.

However, that doesn't mean that there isn't a problem. To me, getClass() is just too facile - every object can only be compared to another one of exactly the same type...ever....even if it's part of a hierarchy.


Yeah, I can't say I recall ever using getClass() in a hierarchy. If the class is final, then that instanceof ThisClass is equivalent to that.getClass() == getClass(). But, if for some reason your design dictates that ThisClass can only ever be equal to instances of ThisClass (no ancestors or descendants), then getClass() is the right way to do it, even if we do happen to get it for free with instanceof + final.

So you run into a few absurdities, just two of which are:
1. B can possibly be compared with A (with compareTo()), but not equated to it.
2. An anonymous class can never be equal to a regular one (nor indeed, to another anonymous one; even if they're created with the same constructor, with the same values, from the same supertype).


You're getting into that "the problem with theoretical discussions" area again. Trying to find a real-world example where I would want objects only to be able to be equal to their own class, but would want to order them relative to themselves AND sub/super classes, well, I just don't see it happening.

I think we're at the point where the rules and guidelines have been laid down, along with the consequences of violating them, and it's time to say, "...but you have to evaluate each case in the context of your design and requirements, and make a judgment call on a case-by-case basis."

Sounds like a Stalinist design pattern to me: "Keep eet seemple comrades."
And I know: I've just proved Godwin's Law yet again.


At least you didn't prove Rule 34. (Of course, by mentioning it, I probably just did. Sorry.)
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Now after reading all your posts several times and making changes to my code, I can see the wealth of information this discussion has and how I had actually not understood enough although I assumed I had.
I also see how patient you guys have been with my stupid posts :-)

Now I realize how important the following check is.


Now that I think of it, it seems instanceof is more the OO way to do things. Because it lets you compare all the cases - an animal with a dog, a dog with a dog, a dog with a cat. How else otherwise you demonstrate that dog is-A animal while also being able to demonstrate that Dog also has some additional properties which let you compare two Dogs( and strictly two Dogs only ) with additional set of parameters. But the moment you compare a Cat with a Dog or either with an animal, you end up comparing only Animal criteria which I believe models the real world more. Because only Animal things are actually comparable in a Cat and Dog or in a Cat/Dog and possibly other animals. And equals should not allow for non comparable things to be compared. Now I see how Winston's equals does it perfect.

May be not making Animal's equals final breaks the transivity requirement but making it a final method also enforces that you can't compare two Dogs with additional Dog criteria you might have. In a way it restricts your design. The getClass() does not demonstrate these relationships among objects but may be a safer approach where you don't care about demonstrating inheritance and/or code duplication while coding superclass comparison criteria in all the subclasses.

Now it seems like I'm all set to read about canEquals :-)

Thank you Jeff and Winston.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Chan Ag wrote:I also see how patient you guys have been with my stupid posts :-)


They weren't stupid. It's a seemingly simple topic with a number of subtle nuances to it that even experienced programmers aren't always fully aware of. And it forced me to think more carefully bout a few things that I'd been getting sloppy with, so win-win!
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Chan Ag wrote:...I can see the wealth of information this discussion has and how I had actually not understood enough although I assumed I had.

Don't worry. You aren't the first; and I'm quite sure you won't be the last. It wasn't until I read the relevant chapter in Joshua Bloch (Effective Java, Item 8) that I realised there was any problem. And canEqual() doesn't solve all your problems; it simply allows you to have equals() work between subclasses in a hierarchy as long as it is NOT overridden.

As Josh Bloch says: "There is no way to extend an instantiable class and add a value component while preserving the equals() contract..."
I think Anjelika Langer might disagree there, but her solution (and a couple of others I've seen) are quite involved - in many cases involving reflection - so I'd consider whether you really need them before you rush to put them in all your programs.

Yet another possibility is to avoid hierarchies altogether in these sorts of situations. Composition is often a fine substitute for inheritance, and you can then build your rules about "what is equal to what" individually.

Now it seems like I'm all set to read about canEquals :-)

Good hunting. This is the article that Mike was referring to; probably not a bad place to start.

Thank you Jeff and Winston.

You're most welcome.

Winston
 
Chan Ag
Rancher
Posts: 1090
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the link, Winston. It's indeed a good place to start. I'm at it already :-)
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!