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