Sprawdź, czy obiekt jest wystąpieniem typu parametru

86

Czy istnieje sposób określenia, czy obiekt jest instancją typu ogólnego?

public <T> test(Object obj) {
    if (obj instanceof T) {
        ...
    }
}

To oczywiście nie działa. Czy jest alternatywa? Tak jak chcę użyć odbicia Java, aby utworzyć wystąpienie klasy, a następnie sprawdzić, czy jest to typ ogólny T.

Nikordaris
źródło

Odpowiedzi:

128

Jedynym sposobem, w jaki możesz to sprawdzić, jest posiadanie Classobiektu reprezentującego typ:

Class<T> type; //maybe passed into the method
if ( type.isInstance(obj) ) {
   //...
}
Mark Peters
źródło
Jeśli nie chcesz otrzymywać typejako parametru metody, być może chcesz go zainicjalizować:Class type = ((T) new Object()).getClass();
JordiVilaplana
9
@JordiVilaplana To nie jest w porządku, da ci java.lang.Object jako klasę. Zobacz to: ideone.com/bxt9Jq
Sri Harsha Chilakapati
3
Użyj:Class<T> type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Ton Snoei
22

Aby rozszerzyć próbkę Marka Petersa, często chcesz zrobić coś takiego:

Class<T> type; //maybe passed to the method
if ( type.isInstance(obj) ) {
   T t = type.cast(obj);
   // ...
}
Kolor brązowofioletowy
źródło
11

Jeśli nie chcesz przekazywać typu klasy jako parametru, o czym wspomniał Mark Peters, możesz użyć następującego kodu. Uznanie dla Davida O'Meary.

  Class<T> type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
                  .getActualTypeArguments()[0];
  if (type.isInstance(obj)) {
      ...
  }
Ton Snoei
źródło
5
DajeType safety: Unchecked cast from Type to Class<T>
Marco Sulla
5

Możesz tego spróbować

// Cast your object to the generic type.
T data = null;
try {
    data = (T) obj;
} catch (ClassCastException cce) {
    // Log the error.
}

// Check if the cast completed successfully.
if(data != null) {
    // whatever....
}
George Siggouroglou
źródło
7
To nie działa! Obsada kończy się sukcesem dla wszystkich typów. Dlatego wyświetla ostrzeżenie o kompilacji „Niezaznaczone rzutowanie”.
Lii
3

Bardziej sensowne byłoby nałożenie ograniczenia na to, gdzie typ Tjest używany do parametryzacji Classtypu. Kiedy podajesz typ, zamiast używać czegoś takiego Class<?>, powinieneś użyć Class<? extends T>.

Chris Dennett
źródło
1
Jeśli chcesz poznać dokładny typ T w czasie wykonywania, ważne jest, aby żądać, aby wywołujący przechodził w Class <T>, a nie Class <? wydłuża T>. Na przykład kod Puce'a nie skompilowałby się z Class <? rozszerza T>.
Theodore Murdock
1

To zadziała (częściowo) tylko wtedy, gdy masz obiekt typu T. Następnie możesz uzyskać klasę tego obiektu, zobaczyć java.lang.Class<T>i sprawdzić, czy jest taka sama jak przedmiot, o którym mowa.

Ale zauważ, że jest to sprzeczne z samym powodem, dla którego mamy genetyki: używanie typu ogólnego jest sposobem na powiedzenie, że nie obchodzi cię, jaki to naprawdę typ (do górnej i dolnej granicy, którą można określić).

Ingo
źródło
Nie ma gwarancji, że Class <?> Zwrócone z wywołania .getClass () w instancji T innej niż null nie jest klasą Class <T>. Najlepsze, co możesz zagwarantować, to to, że jest to klasa <? rozszerza T>.
Theodore Murdock