Let's assume I have four classes: Car
, Convertible
, PickupTruck
and CarManufacturer
.
Car
is the abstract class that Convertible
and PickupTruck
inherit from:
public abstract class Car {
private String name;
private String colour;
//Constructor
}
Convertible
and PickupTruck
both have parameterless constructors:
public class Convertible extends Car {
private boolean roofUnfolded;
public Convertible() {
super("Convertible", "Red");
this.roofUnfolded = false;
}
}
public class PickupTruck extends Car {
private double capacity;
public PickupTruck() {
super("Pickup Truck", "Black");
this.capacity = 100;
}
}
CarManufacturer
stores a List of either Convertibles
or PickupTrucks
.
public class CarManufacturer <T extends Car>{
private List<T> carsProduced = new LinkedList<>();
}
How can I implement a function produceCar()
that calls the parameterless constructor and adds the object to the list? I tried:
public void produceCar(){
this.carsProduced.add(new T());
}
Returning the error: Type parameter 'T' cannot be instantiated directly
The same issues was solved here: https://stackoverflow.com/a/36315051/7380270
With regards to the problem, this works:
public class CarManufacturer <T extends Car> {
private Supplier<T> carType;
private List<T> carsProduced = new LinkedList<>();
public CarManufacturer(Supplier<T> carType) {
this.carType = carType;
}
public void produceCar() {
this.carsProduced.add(carType.get());
}
}
public class Main {
public static void main(String[] args) {
CarManufacturer<Convertible> convertibleCarManufacturer = new CarManufacturer<>(Convertible::new);
convertibleCarManufacturer.produceCar();
}
}
You can add Class<T>
to the CarsManufacturer
, which will preserve the meta-information about the type-parameter at Runtime. This could allow you to instantiate T
, by using the Class#newInstance()
method:
public class CarManufacturer<T extends Car> {
private List<T> carsProduced = new LinkedList<>();
private Class<T> clazz;
public CarManufacturer(Class<T> clazz) {
this.clazz = clazz;
}
public void produceCar() throws IllegalAccessException, InstantiationException {
this.carsProduced.add(clazz.newInstance());
}
}
You can then use it like this:
CarManufacturer<Convertible> carManufacturer = new CarManufacturer<>(Convertible.class);
carManufacturer.produceCar();
Even though this should work, keep in mind that there are few notes that are worth mentioning:
Class<T>
member, just to get access to the type-parameter replacement at Runtime. I would rather add a (T instance)
parameter to the produceCar
method signature and directly add this instance to the list. Since you instantiate the CarManufactured
by explicitly specifying the type-parameter, then there's no need to keep that Class<T>
, because you already have the awareness of what the parameter is.produceCar
method to something more related to what the method does - for example, saveCar()
or addCar()
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With