6

Suppose I have this

interface Movable
{//some stuff}

And I have

class Car implements Movable
{//some stuff}

And also maybe I have

class Bike implements Movable
{//some stuff}

I noticed that if I had this:

ArrayList<Movable> movableThings = new ArrayList<Movable>();
movableThings.add(some kind of Car)
movableThings.add(some kind of Bike)
movableThings.add(some kind of Bike)

This can be called:

for(Movable m: movableThings)

But if I call this I get incompatible types:

for(Bike b: movableThings)

Can someone explain, and maybe offer a better way? I know I can use foreach Movable m: movableThings and then use instanceof to check for Bikes but is there another way?

Edit: alright thanks for clarifying guys... so I guess I either use instanceof or redesign my game

razlebe
  • 7,134
  • 6
  • 42
  • 57

4 Answers4

10

I would not recommend using instanceof. The whole point of two types implementing a common interface is that, when using the interface, consumer code shouldn't be concerned with the specific implementation. I tend to get very suspicious when I see instanceof outside of equals().

Use polymorphic dispatch instead of instanceof if you want different behaviors from different implementations:

interface Movable
{
    void move();
}

class Bike implements Movable
{
    public void move()
    {
        // bike-specific implementation of how to move
    }
}

class Car implements Movable
{
    public void move()
    {
        // car-specific implementation of how to move
    }
}

The implementation-specific method will be called on each type:

for (Movable m : movableThings)
{
    m.move();
}

If you only want to iterate over Bike types, create a collection that only consists of Bikes:

List<Bike> bikes = new ArrayList<Bike>();
// etc...

for (Bike bike : bikes)
{
    // do stuff with bikes
}

N.B. You should almost always declare the collection as a List (an interface) rather than an ArrayList (an implementation of the interface).

See also

If you haven't already, you might also want to read though The Java Tutorials: Interfaces and Inheritance.

Community
  • 1
  • 1
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 1
    +1 yes, of course you are right. @some Java amateur the common methods of derived classes should be put in the interface. – Heisenbug Jun 09 '11 at 17:13
2

You do need to use instanceof. You may want to write a filter function to make it reusable.

That being said, this is probably a case where you want to use inheritance to allow the same method to be called on both classes in the same way.

John Gietzen
  • 48,783
  • 32
  • 145
  • 190
  • that is unfortunate... I didnt want to resort to instanceof because I have nested foreach loops and nested ifs inside those nested foreach loops will make it loop quite messy well thanks for the confirmation – some Java amateur Jun 09 '11 at 17:00
  • 1
    @someJavaamateur, do you mind posting a little bit more of what would be in that `//somestuff` section? Maybe there is a better way, altogether. – John Gietzen Jun 09 '11 at 17:01
  • The second sentence nails it - that's the whole _point_ of the two types implementing a common interface. – Matt Ball Jun 09 '11 at 17:01
2

Because your ArrayList is defined to be

 ArrayList<Movable>

the the get method of your ArrayList will return a type Movable. You need to cast it manually if you are sure about the runtime type (use instanceof to check it).

for(Movable m: movableThings){
      if (m instanceof Car){
            Car car = (Car)m;
      }
}
Heisenbug
  • 38,762
  • 28
  • 132
  • 190
  • 1
    That is a strong code smell, however. If you only want to work with Bikes, this is not the right way to do it. – Matt Ball Jun 09 '11 at 17:00
  • I think he is using an ArrayList to store both Bikes, Car and so on. – Heisenbug Jun 09 '11 at 17:02
  • Yes my arraylist of movable things has both bikes and cars because at some point i use foreach(moveable m: movableThings) to call m.move() – some Java amateur Jun 09 '11 at 17:03
  • @Matt Ball: Could you explain me a better solution, if ArrayList stores both Bikes and Car? – Heisenbug Jun 09 '11 at 17:06
  • unfortunately the arraylist is continuously changing; things get removed and added all the time so creating a new list isn't really a good idea but thanks – some Java amateur Jun 09 '11 at 17:09
  • @some is the `move()` method defined in the `Movable` interface? If not, **it should be.** – Matt Ball Jun 09 '11 at 17:10
  • 1
    it is defined in the interface however, sometimes i might want to call move for only bikes from the list – some Java amateur Jun 09 '11 at 17:11
  • @some that definitely hints at a design problem. If you need to be able to control bikes moving separately from cars, **use two separate lists.** – Matt Ball Jun 09 '11 at 17:14
  • alright let me clarify, I might have a design problem/ the Movable interface also includes a draw function and in a Loop in the game/ sometimes only certain things are moved/ but everything is always drawn/ because of double buffering/ hm... I'll think about using separate lists – some Java amateur Jun 09 '11 at 17:17
0

This is where Google Guava or a similar collection library can be really beneficial. You'll find tons of other uses for it so it's not a hard thing to justify including in your project.

In Guava:

for (Bike bike : Iterables.filter(movableThings, Bike.class) ) {
    //now you only have bikes
}
Mark Peters
  • 80,126
  • 17
  • 159
  • 190