简体   繁体   中英

Java Generics and Polymorphism - how to narrow down generic type at runtime

Here is the example code:

public class Whatever
{
  public static void main(String[] args)
  {
    LazyManufacturer manufacturer = new LazyManufacturer();
    Porsche oldPorsche = new Porsche();
    Porsche newPorsche = new Porsche();
    manufacturer.updateCar(oldPorsche, newPorsche);
    // for a car that I do not know the brand of, I would instantiate Car directly. So Car cannot be abstract
  }
}

public class Car {
  private String carCommonAttribute;

  public void updateAccordingTo(Car car) {
    carCommonAttribute = car.carCommonAttribute;
    System.out.println("common updated");
  }
}

public class Porsche extends Car {
  private String porscheExclusiveAttribute;

  public void updateAccordingTo(Porsche car) {
    super.updateAccordingTo(car);
    porscheExclusiveAttribute = car.porscheExclusiveAttribute;
    System.out.println("porsche exclusive updated");
  }
}

public class Garbage extends Car {
  private String garbageAttribute;
  // similar to Porsche
}

public class LazyManufacturer {
  public <T extends Car> void updateCar(T oldCar, T newCar) {
    oldCar.updateAccordingTo(newCar);
  }
}

I know this is a bad example, but it is good enough for illustrating what I'm trying to achieve.

Right now the output is "common updated" . I would like to see "porsche exclusive updated" as well.

I understand that at compile time, startCar(car) would see start method in Car class as the best fit as its signature perfectly matches what it is looking for. However, is there a way to get around that at runtime? At runtime, startCar would find a better fit for the start method because Porsche is a narrower type, isn't it?

What mark is saying is Change your Car -> start() method to start() instead of start(Car). This way you will be able to achieve what you intent to do.

Usually classes in same hierarchy should have exactly same method signatures so that they override the base class method ( only when behaviour needs to change, of course child classes can also have more methods). There is no need to pass the Car instance to the method, as the object always has access to itself. The passed parameter serves no purpose. For the driver, yes driver needs to have a car as input. Why does the car needs itself as input to call a method?

"At runtime, startCar would find a better fit for the start method because Porsche is a narrower type, isn't it?"

Isn't.

At runtime, JVM has no spare time to choose methods's best fit depending on actual type of given argument. Best fit is chosen at compile time, according to declared type of arguments.

As @markspace said, you probably want to override start(), instead of overloading it. To do so, make signatures of Car.start() and Porche.start() identical. Either remove the argument (it is not used anyway), or declare the argument as Car car in both cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM