Jalict
Jalict

Reputation: 3

Calling a function on a class inside an abstract class list

I'm having some trouble understanding how OOP, Abstract Classes and lists. My current project is in Processing - Just for prototyping of course.

My problem is that I've a list of objects with some of the same variables. So I created an abstract class for them and then a list of all the objects (Abstract class as list) and then added the variant objects to the "abstract" list.

Here is the code - The whole deal can be found just beneath:

ArrayList<Vehicle> vehicles = new ArrayList<Vehicle>();

void setup() {
  vehicles.add(new Motorcycle());
  vehicles.add(new Motorcycle(2,"Yamaha"));
  vehicles.add(new Truck());
  vehicles.add(new Truck(4,"ASU AC2",2));

  print(vehicles);
  vehicles.get(3).dropLastTrailer(); 
}

Truck:

class Truck extends Vehicle {
  int numOfTrailers;

  Truck() {
    super();
    numOfTrailers = 0;
  }

  Truck(int size, String name, int numOfTrailers) {
    super(size, name);
    this.numOfTrailers = numOfTrailers;
    type = "Truck";
  }

  void dropLastTrailer() {
    numOfTrailers--;
    println("Dropped one trailer, the truck now got " + numOfTrailers + " trailers");
  }
}

Vehicle:

abstract class Vehicle {
  int speed, size;
  String name;
  String type;

  Vehicle() {
    this((int)random(0,6),"Unknown Vehicle");
    type = "Vehicle";
  }

  Vehicle(int size, String name) {
    this.size = size;
    this.name = name;
  }

  String toString() {
    return (name + " is " + size + "m long " + type);
  }
}

The code works up until I try to call the "dropLastTrailer" function where it says the method doesn't exist. I guess this is properly because it thinks it's just a Vehicle object, and not a Truck.

How can I fix this?

Full Code can be found here: https://github.com/Jalict/processing-experiments/tree/master/oop_abstract_list

Upvotes: 0

Views: 180

Answers (3)

Sumit Singh
Sumit Singh

Reputation: 15896

Your ArrayList is type of <Vehicle> and Vehicle doesn't have dropLastTrailer() method.

So First you have to Downcast your object into Truck then only you can able to call this function like.

((Truck) vehicles.get(3)).dropLastTrailer();

Upvotes: 0

iluxa
iluxa

Reputation: 6969

Dumb fix: cast

((Truck)vehicles.get(3)).dropLastTrailer(); 

but that's kind of dangerous. How do you know whether that element in a list is indeed a truck?

Better:

Vehicle v = vehicles.get(3);

if (v instanceof Truck) {
  // then we can safely cast
  ((Truck)v).dropLastTrailer(); 
}

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1502746

How would you expect the compiler to know that it is a Truck? You've declared a list of vehicles. Imagine if you were using list.get(0) instead of list.get(3) - then the value would be a reference to a Motorcycle, not a Truck.

You can fix this by casting:

((Truck) vehicles.get(3)).dropLastTrailer();

... but at that point your code is assuming the type of an object within the list, which isn't ideal. You could make this conditional:

Vehicle mightBeTruck = vehicles.get(3);
if (mightBeTruck instanceof Truck) {
    Vehicle truck = (Truck) mightBeTruck;
    truck.dropLastTrailer();
}

That's safer, but it's still not great from a design perspective. Unfortunately the sample given doesn't have enough context to apply it to a real world task - sometimes things like this really are necessary. Usually there are cleaner approaches, but it depends on what you're trying to achieve.

Upvotes: 1

Related Questions