2017-07-19 169 views
3

我們假設我有四個類:Car,Convertible,PickupTruckCarManufacturerJava泛型調用構造函數

Car是抽象類,ConvertiblePickupTruck繼承:

public abstract class Car { 
    private String name; 
    private String colour; 

    //Constructor 
} 

ConvertiblePickupTruck都有參數構造函數:

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商店要麼ConvertiblesPickupTrucks的名單。

public class CarManufacturer <T extends Car>{ 
    private List<T> carsProduced = new LinkedList<>(); 
} 

我怎樣才能實現一個功能produceCar()調用參數的構造函數和將對象添加到列表中?我想:

public void produceCar(){ 
    this.carsProduced.add(new T()); 
} 

返回錯誤:Type parameter 'T' cannot be instantiated directly

回答

5

同樣的問題在這裏得到解決: https://stackoverflow.com/a/36315051/7380270

至於這個問題,這個工程:

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(); 
    } 
} 
2

您可以添加Class<T>CarsManufacturer,這將保留有關在運行時類型參數的元信息。這可能讓你實例化T,通過Class#newInstance()方法:

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()); 
    } 

} 

然後,您可以使用它像這樣:

CarManufacturer<Convertible> carManufacturer = new CarManufacturer<>(Convertible.class); 
carManufacturer.produceCar(); 

即使這應該工作,記住,有幾個注意事項值得一提:

  • 我不會使用Class<T>成員,只是爲了在運行時訪問類型參數替換。我寧願將(T instance)參數添加到produceCar方法簽名中,並直接將此實例添加到列表中。由於您通過明確指定類型參數來實例化CarManufactured,因此您無需保留Class<T>,因爲您已經知道該參數是什麼。
  • 我會將produceCar方法重命名爲與該方法的更多相關內容 - 例如,saveCar()addCar()
+0

那麼有比使用反射更好的方法,但仍然是一個有效的答案。 – Flown