Reputation: 371
I have a superclass(Animal) and two subclasses(Frog and Lion). In my private method below, I'm creating three Lions and one Frog. I am displaying all four of the Animal's weight in my first loop, and all of the Lion's names in the second loop. I get the correct output, but my teacher told me "there is no need for creating two ArrayLists in your main method." I'm guessing he is suggesting that I use my first ArrayList to access the getName() method of my Lion Subclass.
This is how i did it and it was working:
import java.util.ArrayList;
public class AnimalTest {
public static void main(String[] args){
ArrayList<Animal> animalList = createList();
for(int i = 0; i < animalList.size(); i++){
System.out.println(animalList.get(i).getWeight() + " lbs");
}
ArrayList<Lion> lionList = createList();
for(int j = 0; j < 3; j++){
System.out.println(lionList.get(j).getName());
}
}
private static ArrayList createList(){
ArrayList<Animal> list = new ArrayList<Animal>();
list.add(new Lion("Leo I", 530.00));
list.add(new Lion("Leo II", 560.00));
list.add(new Lion("Leo III", 590.00));
list.add(new Frog("Freddie", 7.00));
return list;
}
}
Does he want me to access my getName() function from my Lion class through the same ArrayList list? I was thinking I could do this with some casting, like so:
//ArrayList<Lion> lionList = createList();
for(int j = 0; j < 3; j++){
System.out.println(animalList.(Lion)get(j).getName());
}
But this doesn't work.. I don't understand how I'm supposed to get to my Lion subclass's getName() method without creating a another ArrayList..
Here are the rest of my classes:
public class Animal {
private String genus;
private String species;
private double weight;
private boolean tail;
public Animal(){}
public Animal(String genus, String species){
this.genus = genus;
this.species = species;
}
public String getGenus(){
return genus;
}
public String getSpecies(){
return species;
}
public double getWeight(){
return weight;
}
public void setWeight(double weight){
this.weight = weight;
}
public boolean hasTail(){
return tail;
}
public void setTail(boolean tail){
this.tail = tail;
}
}
public class Lion extends Animal {
private String name;
public Lion(){}
public Lion(String name, double weight){
super("Panthera", "Leo");
this.name = name;
setWeight(weight);
setTail(true);
}
public String getName(){
return name;
}
}
public class Frog extends Animal {
private String name;
public Frog(){}
public Frog(String name, double weight){
super("Lithobates", "Catesbeianus");
this.name = name;
setWeight(weight);
setTail(false);
}
public String getName(){
return name;
}
}
Upvotes: 1
Views: 4295
Reputation: 106390
A parent class cannot access the fields or methods of a child class, since it has no knowledge of what it has implemented.
With that in mind, the logical thing to do is place what you need to access in the Animal
class instead. This means that you're going to pull the name
field up into the parent Animal
class and access it there instead.
Then, you only require one ArrayList
:
ArrayList<Animal> animalList = createList();
for(Animal animal : animalList) {
System.out.println(animal.getWeight());
System.out.println(animal.getName());
}
Further, two very important changes to your createList
method need to happen:
Do not return a raw ArrayList
. Ever. You need to type it correctly.
public ArrayList<Animal> createList() { }
You should not care about it being an ArrayList
or a List
. It's preferable (although not required) to program to the interface of List
instead.
public List<Animal> createList() { }
For bonus points, you could prevent mutations of the list either by making it immutable or using PECS:
public List<? extends Animal> createList() { }
Upvotes: 1
Reputation: 201429
Your createList
function is return a raw-type. Please, don't do that. Also, I recommend you program to the interface. But your second example lionList
would seem to need a createLionList
method. Something like,
private static List<Lion> createLionList() {
List<Lion> list = new ArrayList<>();
list.add(new Lion("Leo I", 530.00));
list.add(new Lion("Leo II", 560.00));
list.add(new Lion("Leo III", 590.00));
return list;
}
Then we can modify the first createList
to add it. Something like,
private static List<Animal> createList() {
List<Animal> list = new ArrayList<>();
list.addAll(createLionList());
list.add(new Frog("Freddie", 7.00));
return list;
}
In your main
method, I would prefer a for-each
loop. And formatted output. Something like,
List<Animal> animalList = createList();
for (Animal a : animalList) {
System.out.printf("Weight: %d lbs, Name: %s", a.getWeight(),
a.getName());
}
Upvotes: 1
Reputation: 14313
You have the right idea, you've just got the syntax for the cast wrong. Try:
((Lion)animalList.get(j)).getName()
Although if both frogs and lions can have names, it would make more sense to just put the getName()
in the Animal
class.
Upvotes: 0