2013-02-27 19 views
8

W C++ można określić typ zwracanej przez funkcję za pomocą parametru, takie jak:Metoda z Generic typ zwracany w Javie

C++

float* myFloat = CollectionClass.ptr<float>(); 
    int* myInt = CollectionClass.ptr<int>(); 

Czy istnieje odpowiednik w języku Java, aby określić typ zwrotu bez dodawania dodatkowych argumentów klasy?

Java

//This doesn't work (due to type erasure) 
    public <T> T getDate() 
    { 
     if (T instanceof Date) 
      return new Date(); 
     if (T instanceof Calendar) 
      return new Calendar(); 
    } 

    Date myDate = getDate<Date>(); 
+0

co to kupi, że nie można osiągnąć, po prostu rzucając bardziej ogólny zwrot do bardziej konkretnego var? – amphibient

+1

zaktualizował pytanie, aby było bardziej zrozumiałe. – Jason

Odpowiedz

16

To perfekcyjnie zadeklarować metodę z podpisem public <T> T getDate().

Jednak niemożliwe jest, aby wdrożyć metodę, która zwraca, co chcesz. To, co metoda wykonuje w środowisku wykonawczym, nie może zależeć od samego parametru typu, ponieważ nie zna jej parametru typu.

Aby uzyskać intuicję, zdaj sobie sprawę z tego, że każdy kod napisany za pomocą generycznych może być również napisany w sposób równoważny bez użycia generycznych, po prostu usuwając ogólne parametry i wstawiając w razie potrzeby rzuty. Oto co oznacza "typ wymazania".

Dlatego, aby sprawdzić, czy metoda byłaby możliwa w rodzajowych, po prostu zapytać, w jaki sposób to zrobić bez rodzajowych:

public Object getDate() 
{ 
    // what would you do here? 
} 

Date myDate = (Date)getDate(); 

Jeśli nie można tego zrobić bez rodzajowych, nie można tego zrobić z Generics albo.

Szablony C++ są całkowicie różne. W przypadku szablonowych funkcji i klas szablony C++ generują "oddzielną kopię" funkcji lub klasy dla każdego argumentu typu, który jest z nią używany. tj. kompilator przyjmuje szablonowy kod i "kopiuje i wkleja" go do wielu wersji, z których każda jest osobna. Dlatego każda kopia kodu jest specyficzna dla określonego argumentu typu i dlatego może używać tego typu w czasie wykonywania.

To dlatego kod szablonu w formacie C++ jest wymagany, aby był dostępny w formie źródłowej, abyś mógł z niego korzystać - nie ma czegoś takiego jak "skompilowane" szablony. Jednak w Javie można użyć skompilowanej klasy ogólnej. Ogólne klasy i metody w języku Java nie zakładają niczego na temat typów, na których mogą być używane.

7

Dobra, teraz z edycji, aby było jasne, że kod jest uwarunkowane T ...

Nie, nie ma nic prostego ciągu Java do tej pracy - ze względu na wpisz wymazanie, jak wspomina twoje pytanie. można przekazać w Class<T>:

public <T> T getDate(Class<T> clazz) 
{ 
    // Now use clazz to work out what to do 
} 

... ale nie można niczego zrobić która zależy od „wartości” samego T w czasie wykonywania, jak to jest po prostu nie wiadomo. Rodzajowych jest nieco anemiczny w Javie, niestety :(


EDIT: Przed edit aby kod warunkowy na T ...

To tylko kwestia określania typu argumentu inaczej:

import java.util.Date; 

class Test { 

    public static <T> T getDate() { 
     return (T) new Date(); 
    } 

    public <T> T getDateInstanceMethod() { 
     return (T) new Date(); 
    } 

    public static void main (String [] args) { 
     Date date = Test.<Date>getDate(); 

     // Compiles fine, but is obviously bogus. 
     String string = Test.<String>getDate(); 

     // And specifying a type argument for an instance method 
     Test test = new Test(); 
     date = test.<Date>getDate(); 
    } 
} 

zawsze preferowane podejście „umieścić argumenty typu tuż przed regularnych argumentów” też, ale tam pójdziemy ...

E DIT: Jak zauważy rgettman, typacja wnioskowania i tak będzie dla ciebie właściwa, więc tak naprawdę nie musisz potrzebować, aby określić argumenty typu w wielu przypadkach. Czasami jednak.

+0

Warto wspomnieć, że czasami można pozwolić kompilatorowi na wyprowadzenie go z celu, więc 'Date date = Test.getDate();' faktycznie działa dobrze w powyższym kodzie. –

+0

jaki byłby cel robienia tego w ten sposób, że nie można by zrobić, gdyby 'getDate' po prostu zwrócił datę? Jakie jest w tym przypadku zastosowanie leków generycznych? – amphibient

+0

@foampile: Więcej pytanie do Jason niż Jon, prawda? (Ale poprawka Jasona na pytanie wyjaśnia ...) –

1

W przypadku Arrays.asList czasami konieczne jest określenie typu zwrotu. Java próbuje "zawęzić" typ zwracania w oparciu o wspólny nadmiar (e) wszystkich argumentów, ale czasami potrzebny jest określony typ. Na przykład,

List<Number> list = Arrays.asList(1, 2, 3); 

Tutaj Arrays.asList zwraca List<Integer> a otrzymasz błąd kompilatora. Aby go zwrócić, należy podać typ ogólny.

List<Number> list = Arrays.<Number>asList(1, 2, 3); 
Powiązane problemy