• Post Reply Bookmark Topic Watch Topic
  • New Topic

ArrayList and Subclass Methods  RSS feed

 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

Working my way from polymorphism into interfaces, but before I go any further I just wanted to check something about a polymorphically configured ArrayList calling a subclass's methods. Very straightforward set up with a inheritance tree of:

Animal
Dog - Cat








When run this returns:

Woof!
DogM
Miaow!
CatM

My only question is about the green comments within my 'main' section i.e.

Have I understood correctly why a.noise() calls the methods it does?
Am I correct to say you must do the down cast to relevant subclass before calling it's methods?

Cheers,

PaulC.
 
Stefan Evans
Bartender
Posts: 1837
10
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Your understanding looks fine to me.


But just to follow through on some bits you haven't explicitly mentioned:



If we added a Pig to the list - what would it display?
How would it be different if the Animal class and the noise() method were abstract?


Also in terms of generic feedback on coding conventions:
- Your methods DogMethod and CatMethod should start with a lower case letter: dogMethod/catMethod
- When declaring variables prefer the interface over the implementation.  So instead of declaring an ArrayList, just declare a List
i.e. the following is preferable



Also in this code:


The instantiation of a new Dog object is unnecessary.
It should just be:

 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stefan Evans wrote:Your understanding looks fine to me.

But just to follow through on some bits you haven't explicitly mentioned:

If we added a Pig to the list - what would it display?

Without checking in Eclipse. My expectation would be:

Woof!
DogM
Miaow!
CatM
Animal Noise
PigM

The reason being that a.noise when referencing a Pig object on the heap, won't find an instance of the noise method. However, it knows that Pig extends Animal so using inheritence it will look in Animal. It will of course find it and then display Animal's bit of text "Animal Noise".

Just checked in Eclipse, and this is indeed what happens....whether my reasoning is correct or otherwise :-)

Thanks for the code tips. Hadn't seen ArrayList defined like that before in the main book I'm learning from. Will use that notation moving forward as it looks neater.

How would it be different if the Animal class and the noise() method were abstract?


Will need to think about that and it's time I left for work. I'll get back to you :-)
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stefan Evans wrote:
How would it be different if the Animal class and the noise() method were abstract?


Ok, had a quick think and my understanding of abstraction is that the first concrete class below the abstracted class needs to define any abstract methods it inherits i.e. if Dog, Cat and Pig all extend Animal (which they do) and Animal and it's single noise() method are now abstract, then all three subclasses would need to define noise(). As such when running my earlier code the Pig iteration, instead of using Animal's noise() will now use its own.

Is this correct?
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mostly, except your original Pig didn't implement its own noise() method.  If, as Stefan proposed, Animal and Animal.noise() were both declared as abstract, you wouldn't be able to put a default behavior of noise() in Animal. So, what would happen?

Aside from that, I believe you're ready to move on. You seem to show a good understanding of the workings of the code you wrote.

One more thing I'll add for you to consider. Is the code below legal? Will it fail at compile time or run time? Why or why not?

And one last thing, before I forget. Please, please, avoid using instanceof. Treat it like a red flag, especially if you're not writing code that will go into some kind of general-purpose library that uses a lot of reflection. Polymorphism and instanceof are incompatible with each other.
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:Mostly, except your original Pig didn't implement its own noise() method.  If, as Stefan proposed, Animal and Animal.noise() were both declared as abstract, you wouldn't be able to put a default behavior of noise() in Animal. So, what would happen?

As I said my understanding is that Pig would need to define noise() as it is a concrete class below an abstract class containing an abstract instance of the noise() method i.e. Pig would have its own noise(). If however, you’re asking what would happen if I didn’t put noise() inside Pig and then ran a.noise() from the ArrayList loop when the list contains a Pig object? Well, without access to my code at the moment I would possibly expect that to give some sort of run-time exception. The reason being a.noise when referencing a Pig object on the heap would go back up the inheritance tree to Animal, find an abstract method and then think “shit” I don’t have an actual definition of that anywhere. At that point an error would occur…maybe. Failing that it will simply recognise a lack of noise() in Pig and do nothing i.e. ride any error.

Junilu Lacar wrote:Aside from that, I believe you're ready to move on. You seem to show a good understanding of the workings of the code you wrote.

Thanks. I like to think of myself as a fairly quick learner. I’m an experienced coder, but just not with Java. But after only 2 or 3 weeks I feel I am getting to know how it thinks. More than that I’m really enjoying the challenge. Just wish I’d done this 10 years ago. Approaching 50 I’m not sure if employers will take me seriously as an option over a 25 years old grad whose done Java since day one of Uni. But, I’m going to give it a go.

Junilu Lacar wrote:One more thing I'll add for you to consider. Is the code below legal? Will it fail at compile time or run time? Why or why not?


Hmmm, ok. I’ll need to take this a step at a time:

Line 1 – Creates Dog ArrayList called fidos
Line 2 – Adds a Dog object to slot 0 of fidos
Line 4 – You are creating a second ArrayList called farm which is a cast of fidos i.e. you’re generating an Animal ArrayList from a Dog one. Ok. Haven’t seen that before but in theory I don’t see why not as Dog is a Subclass of Animal i.e. polymorphism says it should be possible to upward cast like this.
Line 6-7 – Add Cat and Dog objects to the farm Animal ArrayList. As long as Line 4 was ok, then this is definitely ok as it’s classic polymorphism.

Ok. I’d say that will work.

Junilu Lacar wrote:And one last thing, before I forget. Please, please, avoid using instanceof. Treat it like a red flag, especially if you're not writing code that will go into some kind of general-purpose library that uses a lot of reflection. Polymorphism and instanceof are incompatible with each other.

Oh, absolutely agree. The example code in this post is only to get an understanding of some mechanics. For me the main thrust of polymorphism is to allow generic code to be written at a level where the actual subclass instances are totally transparent/irrelevant to the coder i.e. they shouldn’t need to care what the animal classes actually are (just that there are some), and therefore wouldn’t need to change code at a superclass level if a new animal subclass was added.
 
Henry Wong
author
Sheriff
Posts: 23295
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:
Line 4 – You are creating a second ArrayList called farm which is a cast of fidos i.e. you’re generating an Animal ArrayList from a Dog one. Ok. Haven’t seen that before but in theory I don’t see why not as Dog is a Subclass of Animal i.e. polymorphism says it should be possible to upward cast like this.


A cast doesn't actually "create" anything. It doesn't "generate" anything either. What that line does is declare a new reference variable (named farm), which is assigned to the same object as the fidos variable.

Given this information, I will let you try to answer Junilu questions again...

Henry
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Henry Wong wrote:A cast doesn't actually "create" anything. It doesn't "generate" anything either. What that line does is declare a new reference variable (named farm), which is assigned to the same object as the fidos variable.

Given this information, I will let you try to answer Junilu questions again...

Henry

Ah, I can see my mistake.

So Line 4 creates an Animal object reference variable called farm which points to an existing heap Dog object called fidos. As such there is only one ArrayList object on the heap and that is a Dog one. Therefore attempting to put a Pig or Cat object into the ArrayList farm refererences will FAIL (runtime exception or compile error) because farm references a Dog ArrayList. Therefore farm can only be used to add Dogs.

Is this correct?
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just to confirm. I think Lines 6-7 will give a compilation error because they are attempting to put Pig/Cat objects into a Dog ArrayList.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:As I said my understanding is that Pig would need to define noise() as it is a concrete class below an abstract class containing an abstract instance of the noise() method i.e. Pig would have its own noise().

So far so good.
If however, you’re asking what would happen if I didn’t put noise() inside Pig and then ran a.noise() from the ArrayList loop when the list contains a Pig object? Well, without access to my code at the moment I would possibly expect that to give some sort of run-time exception.

Colder...
The reason being a.noise when referencing a Pig object on the heap would go back up the inheritance tree to Animal, find an abstract method and then think “shit” I don’t have an actual definition of that anywhere. At that point an error would occur…maybe.

Warmer about going up the inheritance tree but that thing about an error at that point moved you out colder...
Failing that it will simply recognise a lack of noise() in Pig and do nothing i.e. ride any error.

Colder...
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:Therefore farm can only be used to add Dogs. ... Is this correct?

Not quite. Hint: The question was meant to see if you understood the binding process at compile time.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:I’m an experienced coder, but just not with Java. But after only 2 or 3 weeks I feel I am getting to know how it thinks. More than that I’m really enjoying the challenge. Just wish I’d done this 10 years ago. Approaching 50 I’m not sure if employers will take me seriously as an option over a 25 years old grad whose done Java since day one of Uni. But, I’m going to give it a go.

Don't be too impressed with students coming out of Uni. Four or five years of programming in Java at the Uni level does not constitute a lot of good experience, at least in my experience. If anything, they have probably built up some very bad habits that can only be corrected with the right mentoring and re-education.

Your past coding experience in the field will probably do you much more good and make you more qualified than most new grads. That's assuming whatever you've shown here is a good indication of the kind of "street smarts" that will make you stand out.

Blatant self-promotion warning: What follows is a shameless, self-promoting plug.

If you root around the Ranch into some of my recent and past posts, especially the ones where I discuss design principles, clean code, refactoring, and Agile software development, you might get an idea of the kind of things I look for in candidates for positions on my teams. I pride myself in being able to attract good people to my teams, largely because I make the interview process so difficult and challenging that only those who actually enjoy doing those kinds of exercises will make it through. In another recent thread, I mentioned a need for passion for solving problems and coming up with good solutions and a dedication to craftsmanship as something that will make you stand out from the crowd. If you can show that more than anything, it won't matter much if your competition is 30 years your junior.
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:Colder...

Hmmm, ok. So, Pig doesn't have noise(), although it should as it is a concrete class beneath the abstract version of noise(), so we then go up to Animal. Animal only has an abstract definition of noise(). The question is what happens now i.e. if the only version of noise() you have is the abstract version? Not something I've come across so far. Bear in mind I am not sitting in front of Eclipse here, all my input is coming straight out of head! To be honest I'm struggling to think what might happen, and am resisting the temptation to use Google. Bottom line is if there is nothing to run, then I can't see what would happen, other than nothing. No error, nothing.
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Paul Clements wrote:Therefore farm can only be used to add Dogs. ... Is this correct?

Not quite. Hint: The question was meant to see if you understood the binding process at compile time.

Damn, I thought I'd got that one right. So farm can store more than Dogs?
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:In another recent thread, I mentioned a need for passion for solving problems and coming up with good solutions and a dedication to craftsmanship as something that will make you stand out from the crowd

That is something I hope would stand me in good stead. I love nothing more than getting to grips with how something works, finding out why somethings don't work and making new things which work better than the old things. I feel if I can get in a room with people that becomes clear. Nothing I come out with is paraphrasing, it's all my own interpretation and understanding (for good or bad). Battle for down the line is to get into the room for a Java position with zero workplace experience in it.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:Bottom line is if there is nothing to run, then I can't see what would happen, other than nothing. No error, nothing.

Well, compilers report errors, too, you know...
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Paul Clements wrote:Bottom line is if there is nothing to run, then I can't see what would happen, other than nothing. No error, nothing.

Well, compilers report errors, too, you know...

i.e. it wouldn't compile because noise() isn't defined in Pig?

I had sort of assumed your inference was that it would (somehow) compile and you wanted to know what would result on execution. In my defence I did say that it should be there :-)
 
Sergiu Dobozi
Ranch Hand
Posts: 107
2
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
To me it looks like the casting should give an error, just because it sounds illogical to cast an implementation to a variable of type interface.
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Paul Clements wrote:Therefore farm can only be used to add Dogs. ... Is this correct?

Not quite. Hint: The question was meant to see if you understood the binding process at compile time.


Just tried it i.e.
;

and I get a compilation error stating that "Cannot cast from List<Dog> to List<Animal>".
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu, on reflection I don't see how:



would get past the compiler. The reason being you are attempting to create an Animal ArrayList object ref which, even if the compiler allowed it, would only give access to a Dog ArrayList object. Therefore any other form of Animal (other than Dog) put into AnimalList would fail. As such the compiler throws an error because it could never be sure which type of Animal you are going to put into this in effect, restricted/bound to one Animal subclass, AnimalList.

Cold/Warm? 
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:
Cold/Warm?

Hot, as they say, as an "adult entertainment worker" on payday.
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Paul Clements wrote:
Cold/Warm?

Hot, as they say, as an "adult entertainment worker" on payday.

Heh, thanks :-)

Oh and I appreciate the questions. Really helping me to think deeper about things. Cheers!
 
Tobias Bachert
Ranch Hand
Posts: 86
18
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:The reason being you are attempting to create an Animal ArrayList object ref which, even if the compiler allowed it, would only give access to a Dog ArrayList object. Therefore any other form of Animal (other than Dog) put into AnimalList would fail. As such the compiler throws an error because it could never be sure which type of Animal you are going to put into this in effect, restricted/bound to one Animal subclass, AnimalList.

Note that an ArrayList<Dog> can effectively hold any type of object, thus adding would work fine (but would pollute the List<Dog>).
 
Paul Clements
Ranch Hand
Posts: 99
1
Chrome Eclipse IDE MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What does this line do?
Tobias Bachert wrote:


Haven't seen that construction before.
 
Henry Wong
author
Sheriff
Posts: 23295
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clements wrote:What does this line do?


This line is doing two casts -- and using generic wildcards. The first cast is a cast to a list of unknown types. And the second cast is a cast to a list of animals types. And of course, as you already mentioned, this will break the lists, as it will now be possible to put cats and birds into a list of dogs.

Henry
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!