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

4 Answers 4

11

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.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 yes, of course you are right. @some Java amateur the common methods of derived classes should be put in the interface.
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;
      }
}

9 Comments

That is a strong code smell, however. If you only want to work with Bikes, this is not the right way to do it.
I think he is using an ArrayList<Movable> to store both Bikes, Car and so on.
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()
@Matt Ball: Could you explain me a better solution, if ArrayList<Movable> stores both Bikes and Car?
it is defined in the interface however, sometimes i might want to call move for only bikes from the list
|
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.

3 Comments

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
@someJavaamateur, do you mind posting a little bit more of what would be in that //somestuff section? Maybe there is a better way, altogether.
The second sentence nails it - that's the whole point of the two types implementing a common interface.
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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.