ArrayList.get() returning wrong object type

XML, Perl, Python, and other languages can be discussed here, even if it isn't PHP (We might forgive you).

Moderator: General Moderators

Post Reply
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

ArrayList.get() returning wrong object type

Post by Chris Corbyn »

Code: Select all

//We use an array iterator
import java.util.ArrayList;

/**
 * Main Entry point for Application
 */
class App
{
	/**
	 * Static method main() executed when app starts
	 * @param String arguments
	 */
	public static void main(String[] args)
	{
		Zoo myZoo = new Zoo("Chester");
		myZoo.attachActivityMonitor(new ZooActivityDisplay());
		myZoo.addAnimal(new Monkey("Fred"));
	}
}

/**
 * Abstract class ZooActivityMonitor
 * A plugin API to allow objects to observe changes in the Zoo
 */
abstract class ZooActivityMonitor
{
	/**
	 * An instance of Zoo
	 */
	protected Zoo zoo;
	
	public ZooActivityMonitor() {}
	
	/**
	 * Set the Zoo object for observation
	 * @param Zoo
	 */
	public void setZoo(Zoo theZoo)
	{
		this.zoo = theZoo;
	}
	/**
	 * Abstract method scan() must be overridden by child
	 */
	abstract public void scan();
}

/**
 * An observer which views changes in Zoo and displays info
 */
class ZooActivityDisplay extends ZooActivityMonitor
{
	public ZooActivityDisplay() {}
	
	/**
	 * Abstract method scan()
	 */
	public void scan()
	{
		for (int i = 0; i < this.zoo.animals.size(); i++)
		{
			System.out.println("Here");
		}
	}
}

/**
 * Zoo class
 * Stores animals
 */
class Zoo
{
	/**
	 * The name of this Zoo
	 */
	private String name;
	/**
	 * A container for animals in this Zoo
	 */
	public ArrayList animals;
	private ArrayList monitors;
	
	/**
	 * Constructor
	 * @param String name
	 */
	public Zoo(String myName)
	{
		this.monitors = new ArrayList();
		this.animals = new ArrayList();
		this.name = myName;
	}
	/**
	 * Get the name of this Zoo
	 * @return String
	 */
	public String getName()
	{
		return this.name;
	}
	/**
	 * Add a new Animal to this Zoo
	 * @param String animal
	 */
	public void addAnimal(Animal animal)
	{
		this.animals.add(animal);
		this.runMonitors();
	}
	/**
	 * Add a new activity monitor to this zoo
	 * @param ZooActivityMonitor
	 */
	public void attachActivityMonitor(ZooActivityMonitor a)
	{
		a.setZoo(this);
		this.monitors.add(a);
	}
	/**
	 * Run all monitors currently attached
	 */
	protected void runMonitors()
	{
		for (int i = 0; i < this.monitors.size(); i++)
		{
			this.monitors.get(i).scan();
		}
	}
}

/**
 * An animal which lives in the Zoo
 */
abstract class Animal
{
	/**
	 * The name of this animal
	 */
	protected String name;
	protected int maxTemp = 0;
	protected ArrayList food;
	
	/**
	 * Constructor
	 */
	public Animal(String itsName)
	{
		this.food = new ArrayList();
		this.name = itsName;
	}
	/**
	 * Get the name of this anmial
	 * @return String
	 */
	public String getName()
	{
		return this.name;
	}
	/**
	 * Get the maximum temperature at which this animal can live
	 * @return int
	 */
	public int getMaxTemp()
	{
		return this.maxTemp;
	}
}

//Bit of food for the monkey (not yet used)
abstract class Vegetation {}
class Banana extends Vegetation {}

/**
 * Yeah; it's a Monkey
 */
class Monkey extends Animal
{
	protected int maxTemp = 50;
	
	public Monkey(String itsName)
	{
		super(itsName);
		this.food.add("Banana");
	}
}
The method runMonitors() is throwing an error that scan() doesn't exist in Object().

Code: Select all

gcj --main=App -o runme ZooApplication.java
ZooApplication.java: In class 'Zoo':
ZooApplication.java: In method 'Zoo.runMonitors()':
ZooApplication.java:107: error: Can't find method 'scan()' in type 'java.lang.Object'.
                        this.monitors.get(i).scan();
                                                ^
1 error
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Doh! Without specifiying a type for ArrayList you get Object back so you need to type cast it. Makes sense I guess.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

In the other post i recommended to use a typed collection ( List<Animal>) this makes sure there are only Animals in the collection.. And you can use the foreach operator...

With an untyped collection, you'll have to cast each Object (since from the compilers POV the list contains Objects) to an ZooActivityMontor..

Code: Select all

      for (int i = 0; i < this.monitors.size(); i++)
                {
                        ((ZooActivityMonitor) this.monitors.get(i)).scan();
                } 

vs:

Code: Select all

// java5 ;)
foreach(ZooActivityMonitor monitor: this.monitors) {
       monitor.scan();
}
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

Anyway, i'm having brainfarts... before there were generics, most people made their own typesafe collection as following:

Code: Select all

class AnimalList implements IList {
 private List list;

 public AnimalList() {
  this.list = new list();
 }

 public Add(Animal animal) {
  this.list.add(animal);
 }

 public Animal get(int index) {
  return (Animal) this.list.get(index);
 }

  // other functions that simply call the list functions...
}
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

timvw wrote:Anyway, i'm having brainfarts... before there were generics, most people made their own typesafe collection as following:

Code: Select all

class AnimalList implements IList {
 private List list;

 public AnimalList() {
  this.list = new list();
 }

 public Add(Animal animal) {
  this.list.add(animal);
 }

 public Animal get(int index) {
  return (Animal) this.list.get(index);
 }

  // other functions that simply call the list functions...
}
If that's a common practise I'll remember that thanks :)
Post Reply