2013-04-17 2 views
6

Hallo alle :) Ich versuche, den richtigen Konstruktor in einer Klasse zu wählen. Hier ist der Code:Überprüfung zur Laufzeit, wenn eine Klasse einen spezifischen Konstruktor hat, der Generics verwendet

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; 
    } 
} 

ich Map.class-Map<String, String>.class wechseln möchten. Ich erinnere mich vage daran, dass Generika nur zur Kompilierzeit sind, weshalb sich der Compiler beschweren muss. Wie kann ich zur Laufzeit überprüfen, ob die Klasse den richtigen Konstruktor hat?

Mit freundlichen Grüßen

Antwort

8

Sie wollen stattdessen getGenericParameterTypes() verwenden:

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) { 
    } 
} 

Nun, wenn Sie MyClass() eine Map<String, Integer> nehmen ändern wird es nicht mehr übereinstimmen.

Dies wird viel einfacher mit Guava TypeToken, die eine anonyme Klasse verwendet, um eine parametrisierte Type zu erstellen, die wir vergleichen können.

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

Meine Antwort entfernt; Ich sollte vorsichtiger sein, bevor ich mit der "generics use type desaster" Antwort antworte! Ich würde sagen, wenn du das tust, dann ist fast sicher etwas mit deinem Design nicht in Ordnung! :) – James

0

Klassen funktionieren nicht so in Java. Klassen können zur Laufzeit nicht parametrisiert werden; nur Instanzen. Es gibt nur eine Map.class, anstatt eine separate Klasse für jede generische Implementierung von Map (wie Sie anscheinend angenommen haben). Der folgende Code könnte helfen, dies zu verdeutlichen:

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

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

Während dies für 'Class' gilt, hat Java Unterstützung für die Darstellung eines Typs, der Typparameter hat, nämlich' ParameterizedType' (siehe meine Antwort). Typparameter werden oft in (jedes Mal, wenn Sie ein generisches Feld oder Parameter für Starter deklarieren) kompiliert. Wenn diese Informationen in der Klassendatei nicht verfügbar wären, könnten Sie nicht mit einer Klasse kompilieren, die Generics verwendet. –

Verwandte Themen