2017-08-17 125 views
0

假設我有3個類:Car,ConvertibleGarage返回子類對象的泛型getter

Car是一個抽象類,Convertible繼承:

轉換具有一個稱爲unfoldRoof()特定的方法。

Garage包含一個Car具有以下getCar()方法:

public Car getCar() { 
    return car; 
} 

當訪問在吸氣劑的Car屬性,我無法使用特定Convertible方法unfoldRoof()

我怎樣才能建立一個通用吸氣,返回子類而不是抽象父類

+3

1.您可以只是其返回,而不是汽車敞篷。 2.如果Car *不是*敞篷車,並且沒有該方法,會發生什麼情況? – Carcigenicate

+0

如果您確定它是一輛敞篷車,您還可以將結果投射到一輛敞篷車並調用unfoldRoof()。或者在鑄造之前檢查它是否實際上是敞篷車(使用instanceof)。 –

+0

@KostasStamos,我寧願保持它的通用性,因爲我需要實現更多的兒童類汽車。 –

回答

1

它是一種能力,所以使用可選:

class Car { 
    <C extends Car> Optional<C> as(Class<C> type) { 
     return type.isInstance(this) 
       ? Optional.of(type.cast(this)) 
       : Optional.empty(); 
    } 
} 

Car car = new Convertible(); 

car.as(Convertible.class).ifPresent(convertible -> { 
    convertible.unfoldRoof(); 
}); 

順便說一句。繼承/敞篷車一般是不是真的需要,你可以有接口,如

Interface Convertible { 
    void unfoldRoof(); 
} 

然而這將需要在地圖領域或安裝等特徵/能力。

1

運行時特定類型的通用接口

您可以指定一個擴展的返回類型一般

public abstract Car <CarType extends Car>{ 
    public abstract CarType getTypedCar(); 
} 

...然後...

public class Convertable extends Car<Convertable> { 
    public <Convertable> getTypedCar(){ 
    return this; 
    } 
} 

但你會仍然需要知道當你做了什麼類型getTypedCar()

Convertable convertable = car.getTypedCar(); 

,這將是相同的(只要運行時類型安全行)不泛型化,並從容器盛裝接口實例

Convertable convertable = (Convertable)car; 

運行時特定類型

當您想要Garage知道它所持有的Car的運行時類型時,就會出現問題。您希望它保存任何Car,但您希望它在運行時返回特定類型,這在編譯時並不知道,因此只能定義爲返回與特定類型相同的對象;在這種情況下,Car。 你可以通過使Garage只有像@Valentin Ruano建議的Convertables來解決這個問題,但在現實生活中,這是一個愚蠢的想法,因爲你的對象不能像他們應該的那樣表示真實世界對象。即你能建立一個只需要敞篷車的車庫?!

您的需求

這一切都取決於你的需求。例如,你是否需要知道什麼類型的汽車將其從Garage中刪除?或者你可以只返回Car然後使用上面的解決方案做getTypedCar()?同樣,你需要知道(假定)汽車的類型,但這需要在某個地方進行,以便靈活。

把這個假設將是對Garage的吸氣器的另一個地方,你可以有一個方法getCar(Class carType),並把它拋出一個NoSuchCarException如果所需的車型是不存在的,否則返回一個類型的carType

+1

我認爲他的意思是'''Garage'''有一個汽車領域和getter,並不是說汽車有自己的吸氣器或其他同類型的汽車。 –

+0

我明白了。答案擴大了,但實質上並沒有改變。 –

0

你可以爲剛剛返回的汽車定義unfoldRoof(),什麼也不做。

0

最優雅的解決方案是讓Garage通用:

abstract class Car { 
    String make(); 
    int year(); 
    //... 
} 

class Convertible extends Car { 
    void unfoldRoof() { /* whatever */ } 
} 

class Garage<C extends Car> { 

    private C car = null; 

    public Garage() {} 

    public boolean isEmpty() { return car == null; } 

    public C getCar() { return car; } 

    public void park(final C car) { 
     if (!isEmpty()) { 
      throw new IllegalStateException("Garage is full!!"); 
     } else { 
      this.car = car; 
     } 
    } 

    public C exit() { 
     if (isEmpty()) { 
      throw new IllegalArgumentException("There is no cars in garage"); 
     } else { 
     final C exitingCar = car; 
     car = null; 
     return exitingCar; 
     } 
    } 
} 

class Main { 

    public static void main(String[] args) { 

     final Garage<Convertible> myGarage = new Garage(); 
     final Convertible car = ...; 
     myGarage.park(car); 

     //... 

     car = myGarage.getCar(); 
     car.unfoldRoof(); 
    } 

}