2013-02-12 37 views
7

Mam problem ze zrozumieniem taka metoda rodzajowa inwokacji:Typowa metoda inwokacja z <T>

object = ObjectGenerator.<T> getObject(objectName); 

Nadchodzi kontekst dla powyższej sytuacji:

class GenClass<T> { 

    private T object; 

    // ... some code 

    public void initObject(String objectName) { 
     object = ObjectGenerator.<T> getObject(objectName); 
    } 
} 

class ObjectGenerator { 

    public static <T extends Object> T getObject(String name) { 
     // some code 
     return someObject; 
    } 
} 

Powstaje pytanie, jaką rolę odgrywa <T> przed getObject(objectName) wezwanie?

+1

+1, ponieważ wcześniej tego nie widziałem. –

+0

Nie pytam o sens, ale o jedną linię kodu. Mogę zmienić podpis metody na ' T getObject (nazwa łańcucha, klasa clazz)' - to nie ma znaczenia. Tylko ta jedna linia z inwokacją tej metody z '' jest myląca dla mnie – emka86

Odpowiedz

7

Uwaga: w podanym przykładzie, ObjectGenerator.getObject(objectName); powinno się skompilować dobrze.

W niektórych sytuacjach, mechanizm typu wnioskowanie nie można rozwiązać fakt, że w:

T object; 
object = ObjectGenerator.getObject(objectName); 

zwracany typ powinien być T. W takim przypadku musisz udzielić kompilatorowi niewielkiej pomocy, wyraźnie wskazując oczekiwany typ zwracania.

Oto wymyślony przykład, gdzie trzeba wyraźnie określić typ rodzajowy:

class Example { 
    public static <T> List<T> m1() { 
     return m2(Arrays.<T> asList()); //Arrays.asList() would not compile 
    } 
    public static <T> List<T> m2(List<T> l) { 
     return l; 
    } 
} 
+0

W jakich sytuacjach "mechanizm wnioskowania typu" nie byłby w stanie wiedzieć, jaki powinien być zwracany typ? – asteri

+0

@Jeff Dodałem przykład - dokładne sytuacje, kiedy tak się dzieje, zależą od wyniku zastosowania zasad wnioskowania o typie (http://docs.oracle.com/javase/specs/jls/se7/html/jls- 15.html # jls-15.12.2.7), które w wersji pdf JLS mają około 12 stron, więc nie jesteśmy do końca pewni. Ostatecznie na to patrzę: albo kompiluje się bez wyraźnego typu i jestem szczęśliwy, albo nie, a ja po prostu go dodaję ... – assylias

+0

Tak, mam to! To dla mnie bardzo dobre wytłumaczenie i spojrzenie na tę specyfikację ze swojego linku. Sądzę, że jest jeszcze wiele nieprzyjemnych sytuacji do odkrycia! :) – emka86

0

object może być dziecko T.

Oczywiście getObject powinny lepiej zostały zdefiniowane:

public static <T> T getObject(Class<T> objectClass, String name) { 
    return objectClass.getConstructor(String.class).newInstance(name); 
    //return objectClass.getConstructor().newInstance(); 
} 

inaczej jest bezpieczna konstrukcja typu nie możliwe, ze względu na tzw typu skasowaniem.

-1
object = ObjectGenerator.getObject(objectName); 

zawsze zwraca obiekt obiektu, ponieważ jesteś wywołanie metody statycznej. Dla wyraźnie coraz rodzajowy obiekt użyłeś dla T, w kodzie,

object = ObjectGenerator.<T> getObject(objectName); 

<T> jest używany w kontekście statycznej. W przypadku nie statycznego wywołania nie jest to konieczne.

+0

-1 Kontekst statyczny nie ma nic wspólnego z jawnym podawaniem argumentów typu. –

+0

dzięki za oświecenie mnie :) – prasanth

0

Znalazłem coś tutaj: https://stackoverflow.com/a/338906/443427 może ci pomóc.

Z tego co czytałem może reprezentować ogólny, że kompilator musi używać do obliczania retuned typ wartości, aby przejść rodzajową naprzód

jako notatkę to również działać poprawnie (sprawdź ObjectGenerator różni się od T):

public class ObjectGenerator<X> { 
    public static <T extends Object> Set<T> getObject(String name) { 
    // some code 
    return null; 
    } 
} 
0

ja nie całkowicie zgadzam się z przyjętą odpowiedzi, w którym jest napisane:

w takim przypadku trzeba dać kompilator trochę pomocy jawnie wskazując oczekiwany typ zwrotu.

To nie brzmi dobrze dla mnie. Ponieważ rozumiem metodę ogólną i wnioskowanie typu, typ podany w nawiasach kwadratowych nie wskazuje bezpośrednio na typ powrotu metody ogólnej. Typem typu T może być typ zwracany, typ argumentu, typ zmiennej lokalnej powiązany z metodą ogólną.

W rzeczywistości, dzięki mechanizmowi wnioskowania typu, w większości przypadków nie trzeba określać parametru typu T (nie tylko w niektórych sytuacjach). W twoim przykładzie, <T> można bezpiecznie pominąć w wywołaniu metody ObjectGenerator.<T> getObject(objectName), jak w większości innych przypadków. Dzieje się tak dlatego, że typ T metody ogólnej można łatwo wywnioskować z typu, do którego wynik jest przypisany, lub zwrócić. Innymi słowy, ponieważ deklarujesz private T object przed wywołaniem metody, typ T zostanie pomyślnie wywnioskowany jako T.

Moje roszczenie może być wsparte przez następujące oświadczenie od a definitive tutorial:

Rodzaj wnioskowanie jest zdolność kompilatora Java, aby spojrzeć na każdej metody inwokacji i odpowiadające im zgłoszenie, aby określić typ argumentu (lub argumenty) które sprawiają, że inwokacja ma zastosowanie. Algorytm wnioskowania określa typy argumentów i, jeśli jest dostępny, typ, dla którego wynik jest przypisywany lub zwracany. Wreszcie, algorytm wnioskowania próbuje znaleźć najbardziej konkretny typ , który działa ze wszystkimi argumentami.

Dwa przykłady dotyczące sposobu działania wnioskowanie:

static <T> T pick(T a1, T a2) { return a2; } 
Serializable s = pick("d", new ArrayList<String>()); 

typu T jest wywnioskować jak Serializable na podstawie zadeklarowanego typu cesjonariuszem.

public static <U> void addBox(U u, java.util.List<Box<U>> boxes) {} 
BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes); 

typu U wnioskuje jak Integer podstawie rodzaju przechodzi argument (tj. Integer.valueOf(10) jest typu Integer). Dlatego też <Integer> można bezpiecznie pominąć w powyższym wywołaniu metody.

Podsumowując, chyba że nie jesteśmy w stanie wywnioskować parametru typu metody ogólnej od jego typu argumentu lub typu, któremu przypisywany jest wynik lub zwracany (podczas wywoływania metody), możemy bezpiecznie pominąć specyfikację typu tuż przed wywołaniem metody.

Powiązane problemy