0

I was practicing for AP computer science and came across this question:

Consider the following interface and class declarations. Which of the following can be used to replace /* expression */ so that getTotalMileage returns the total of the miles traveled for all vehicles in the fleet?

public interface Vehicle
{
    /** @return the mileage traveled by this Vehicle */
    double getMileage();
}

public class Fleet
{
    private List<Vehicle> myVehicles;
    /** @return the mileage traveled by all vehicles in this Fleet */
    
    public double getTotalMileage()
    {
        double sum = 0.0;
        for (Vehicle v : myVehicles)
        {
            sum += /* expression */;
        }
        return sum;
    }
    // There may be instance variables, constructors, and methods are not shown.
}

Options: (a) v.getMileage()

(b) getMileage(v)

(c) Vehicle.get(v).getMileage()

(d) myVehicles.get(v).getMileage()

(e) This code will not compile because no methods can be called from a List interface reference variable.

The list myVehicles stores objects of type vehicle right?

If so, Shouldn't there be a compile time error while running this? As we are creating objects of type Vehicles which is an interface.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 4
    "As we are creating objects of type Vehicles which is an interface" - which line of code do you think is *creating* an instance of the `Vehicle` interface? – Jon Skeet Apr 25 '23 at 17:18
  • Replace `sum += /* expression */;` with `sum += v.getMileage();` – azbarcea Apr 25 '23 at 17:21

4 Answers4

3

This is called Polymorphism. https://en.wikipedia.org/wiki/Polymorphism_(computer_science)

The list does not have to specify the concrete types, but may contain any type(class) that implements the Vehicle.

So in this case if you had classes

class BMW implements Vehicle { //implement getMileage() method }
class Ford implements Vehicle { //implement getMileage() method }

You could add both BMWs or Fords to the List<Vehicle>

List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(new BMW());
vehicles.add(new Ford());

When iterating over the vehicles, the getMileage() method would call the method of particular instance class.

levangode
  • 406
  • 2
  • 12
1

Note this very important bit:

// There may be instance variables, constructors, and methods are not shown.

While you are correct that new Vehicle() is not a legal statement, this note in the problem allows for additional code like the following:

final class Car implements Vehicle {
  private final double mileage;
  Car(double mileage) {
    this.mileage = mileage;
  }
  public double getMileage() {
    return mileage;
  }
}

Then one could add the result of new Car(10.0) to the fleet of vehicles.

(If you are worried that a class is not "an instance variable, constructor, or method," one can "implement" Vehicle with a reference to any method that takes no arguments and returns a double.)

Thus, the correct answer is "(a), v.getMileage()"

erickson
  • 265,237
  • 58
  • 395
  • 493
1

This is perfectly allowable, and is common in production code. At no point does the code require you to actually instantiate the interface "directly"; rather, the list contains objects that implement the Vehicle interface.

That being said, the correct answer to the question is (a): v.getMileage(). The key insight is that you don't particularly care what kind of vehicle you've been given - all that you care about is that the object in question "promises" that it implements the getMileage() method.

The ability to do this is critical to several design patterns, such as the Factory pattern, where the factory method's return type will either be an interface or a base class.

This is also commonly used in automated testing, where you may want to replace certain components with special versions of the component. This is particularly the case if the component interacts with an external component, such as a web service. For example, I use a library called Moq, which (at risk of oversimplification) allows you to easily create "fake" implementations of interfaces for testing.

0

In Java isn't it impossible to make objects of interface type?

This is true, but no one said you can't create instances of the interface. Note also that Java has anonymous types (See How are Anonymous inner classes used in Java?), so it is entirely possible to create an object which implements the interface without (explicitly) declaring a class:

Vehicle myVehicle = new Vehicle() {
  @Override
  public double getMileage() {
    return 199879.5;
  }
};

Since Java 8, it can even be shortened to just:

Vehicle myVehicle = () -> 199879.5;
smac89
  • 39,374
  • 15
  • 132
  • 179