2013-04-17 23 views
6

Witaj wszystkich :) Próbuję wybrać właściwy konstruktor w klasie. Oto kod:Sprawdzanie w środowisku wykonawczym, jeśli klasa ma określonego konstruktora, który używa generics

Constructor[] constructors = targetClass.getConstructors(); 
Constructor goodConstructor = null; 
for (Constructor constructor : constructors) { 
    Class[] parameterTypes = constructor.getParameterTypes(); 
    if (parameterTypes.length = 1 && parameterTypes[0].equals(Map.class)) {//here 
     goodConstructor = constructor; 
    } 
} 

Chcę przejść z Map.class do Map<String, String>.class. Niejasno pamiętam, że generics są przeznaczone tylko do kompilacji, dlatego kompilator narzeka. Jak mogę sprawdzić w czasie wykonywania, czy klasa ma odpowiedni konstruktor?

poważaniem

Odpowiedz

8

Chcesz użyć getGenericParameterTypes() zamiast:

public class FindConstructor { 

    public static void main(String[] args) throws IOException { 
     for (Constructor<?> constructor : MyClass.class.getConstructors()) { 
      Type[] parameterTypes = constructor.getGenericParameterTypes(); 
      if (parameterTypes.length == 1 && parameterTypes[0] instanceof ParameterizedType) { 
       ParameterizedType parameterizedArg = (ParameterizedType) parameterTypes[0]; 
       if (parameterizedArg.getRawType() != Map.class) { 
        continue; 
       } 

       if (parameterizedArg.getActualTypeArguments()[0] != String.class) { 
        continue; 
       } 

       if (parameterizedArg.getActualTypeArguments()[1] != String.class) { 
        continue; 
       } 
      } 
      System.out.println("found constructor " + constructor); 
     } 
    } 
} 

class MyClass { 
    public MyClass(Map<String, String> map) { 
    } 
} 

Teraz po zmianie MyClass() wziąć Map<String, Integer> nie będzie już mecz.

Staje się to o wiele łatwiejsze dzięki Guva TypeToken, które wykorzystuje anonimową klasę do sparametryzowania Type, którą możemy porównać.

Type mapStringString = new TypeToken<Map<String, String>>(){}.getType(); 
for (Constructor<?> constructor : MyClass.class.getConstructors()) { 
    Type[] parameterTypes = constructor.getGenericParameterTypes(); 
    if (parameterTypes.length == 1 && parameterTypes[0].equals(mapStringString)) { 
     System.out.println("found constructor " + constructor); 
    } 
} 
+0

Usunięto moją odpowiedź; Powinienem być bardziej ostrożny, zanim odpowiem na pytanie "odpowiedź generics type erasure"! Powiedziałbym, że jeśli to robisz, prawie na pewno jest coś nie tak z twoim projektem! :) – James

0

Klasy nie działają w ten sposób w języku Java. Klasy nie można sparametryzować w czasie wykonywania; tylko instancje. Jest tylko jeden Map.class, a nie (jak się wydaje zakładałeś) oddzielna klasa dla każdej ogólnej implementacji mapy. Poniższy kod może pomóc w wyjaśnieniu:

Map<String,String> m1 = new HashMap<>(); 
    Map<Object,Long> m2 = new HashMap<>(); 

    System.out.println(m1.getClass() == m2.getClass());//prints "true" 
+0

Chociaż jest to prawdziwe w 'Klasy', Java ma wsparcie dla reprezentowania typu, który ma parametry typu, mianowicie' ParameterizedType' (zobacz moją odpowiedź). Parametry typu są dość często kompilowane (za każdym razem, gdy zadeklarujesz ogólne pole lub parametr, na początek). Jeśli ta informacja nie byłaby dostępna w pliku klasy, nie byłaby możliwa kompilacja z klasą, która używa generycznych. –