2013-08-11 38 views
6

Jestem prawie pewien, że jest to bezpieczny rodzaj, ale chciałem tylko sprawdzić, jak Eclipse prosi mnie o umieszczenie adnotacji @SuppressWarnings("unchecked").Czy mój kod jest bezpieczny?

Map<String, IFace> faces; 

public <T extends IFace> T getFace(String key) 
{ 
    return (T) faces.get(key); 
} 
+5

Odpowiadając na moje własne pytanie: Nie, to nie dlatego, że mogę mieć dwie RÓŻNE klasy "ClassA' &" ClassB' które implementują 'IFace' w' faces'. W środowisku wykonawczym 'T' może być' ClassA' lub 'ClassB'. – Cheetah

+0

Znana gwiazdka, ponieważ jestem bardzo zainteresowany podobnym problemem –

+2

Dlaczego te generyczne są tutaj? Jeśli odwołujesz się do rzeczy typu "IFace", to nie potrzebujesz generycznych/castingowych –

Odpowiedz

4

To nie jest bezpieczny rodzaj. Jesteś upcasting tutaj, więc jeśli rzutujesz na niekompatybilną klasę pochodną, ​​w pewnym momencie natkniesz się na błąd.

Na przykład, jeśli A_Face i B_Face oba rozszerzają się o IFace. W pewnym momencie możesz rzucić B_Face jako A_Face, który nie jest bezpieczny dla typu.

0

Spójrz na skrajny przypadek. Powiedzmy IFace jest acutally Object, następnie kod wygląda następująco:

static Map<String, Object> myMap = new HashMap<>(); 

public static void main(String[] args) throws Exception { 
    myMap.put("ONE", 1); 
    myMap.put("TWO", "TWO"); 
    myMap.put("THREE", new Date()); 

    final Calendar calendar1 = getThing("ONE"); 
    final Calendar calendar2 = getThing("TWO"); 
    final Calendar calendar3 = getThing("THREE"); 
} 

public static <T> T getThing(String key) { 
    return (T) myMap.get(key); 
} 

Więc stawiamy na class niż extends Object do swojej Map (SO żadnego class).

Ale kiedy zadzwonisz pod numer getThing, wykonujesz niejawne rzutowanie na pożądany typ. Powinno być całkiem oczywiste, że mogę zadzwonić pod numer getThing z dowolnym numerem class i będzie on na ślepo próbował go rzucić.

W powyższym przykładzie umieszczam pewne rzeczy w moim Map, a następnie próbuję pobrać je wszystkie jako Calendar s.

0

Klasycznym sposobem obsługi to jest z „typesafe heterogenicznej kontenera”:

Map<Class<?>, IFace> faces; 

public <T extends IFace> T getFace(Class<T> key) { 
    return t.cast(faces.get(key)); 
} 

użyć klasy interfejsu jako klucz, zamiast łańcucha, a następnie można wykorzystać klasę przeszedł jako klucz do bezpiecznego rzucenia wartości zwracanej do właściwego typu.