Frage

Ich brauche einige reflektierende Methodenaufrufe in Java zu machen. Diese Anrufe werden Methoden enthalten, die Argumente haben, die primitive Typen (int, double, etc.). Die Art und Weise solche Typen zu spezifizieren, wenn die Methode reflektiv aufzublicken ist int.class, double.class, etc.

Die Herausforderung besteht darin, dass ich eine Eingabe von einer externen Quelle bin zu akzeptieren, die die Typen dynamisch angeben werden. Deshalb muss ich auch dynamisch mit diesen Klassenreferenzen kommen. Stellen Sie sich eine getrennte Datei eine Liste von Methodennamen mit Listen von Parametertypen:

doSomething int double
doSomethingElse java.lang.String boolean

Wenn die Eingabe etwas wie java.lang.String war, weiß ich, ich Class.forName("java.lang.String") diese Klasse Instanz zurück nutzen könnte. Gibt es eine Möglichkeit, dass die Methode zu verwenden, oder eine andere, die primitive Art Klassen zurück zu bekommen?

Edit: Vielen Dank an alle Teilnehmer. Es scheint klar, dass es keine integrierte Möglichkeit ist sauber zu tun, was ich will, also werde ich für die Wiederverwendung der ClassUtils Klasse aus der Spring-Framework zu begleichen. Es scheint einen Ersatz für Class.forName enthalten (), die mit meinen Anforderungen arbeiten.

War es hilfreich?

Lösung

Der Spring-Framework enthält eine Utility-Klasse Quellcode der Methode e gefunden werden kann. G. hier auf ihren öffentlichen Repository. Die Klasse Quellcode ist unter der Apache-2.0-Modell lizenziert.

Beachten Sie jedoch, dass der Algorithmus eine hartcodierte Karte von primitiven Typen verwendet.


Edit:. Dank commen Dávid Horváth und Patrick für den Defekten Link Hinweis auf

Andere Tipps

Die Class Instanzen für die primitiven Typen sind erhältlich, wie Sie unter Verwendung des z.B. int.class, aber es ist auch möglich, die gleichen Werte zu erhalten etwas wie Integer.TYPE verwenden. Jede Wrapper-Klasse enthält ein statisches Feld, TYPE, die die entsprechende primitive Klasseninstanz hat.

Sie können nicht die primitive Klasse über forName erhalten, aber man kann es aus einer Klasse erhalten, die leicht verfügbar ist. Wenn Sie unbedingt Reflexion verwenden müssen, können Sie so etwas wie dies versuchen:

Class clazz = Class.forName("java.lang.Integer");
Class intClass = clazz.getField("TYPE").get(null);

intClass.equals(int.class);         // => true

Wahrscheinlich brauchen Sie nur die Grundelemente abzubilden und für den Rest der Klassen führen die „forName“ Methode:

Ich würde so etwas wie:

void someWhere(){
     String methodDescription = "doSomething int double java.lang.Integer java.lang.String"
     String [] parts = methodDescription.split();
     String methodName= parts[0]
     Class [] paramsTypes = getParamTypes( parts ); // Well, not all the array, but a, sub array from 1 to arr.length..  

    Method m = someObject.class.getMethod( methodName, paramTypes );
    etc. etc etc.
}

public Class[] paramTypes( String [] array ){
     List<Class> list = new ArrayList<Class>();
     for( String type : array ) {
         if( builtInMap.contains( type )) {
             list.add( builtInMap.get( type ) );
          }else{
             list.add( Class.forName( type ) );
          }
     }
     return list.toArray();
}  

    // That's right.
Map<String,Class> builtInMap = new HashMap<String,Class>();{
       builtInMap.put("int", Integer.TYPE );
       builtInMap.put("long", Long.TYPE );
       builtInMap.put("double", Double.TYPE );
       builtInMap.put("float", Float.TYPE );
       builtInMap.put("bool", Boolean.TYPE );
       builtInMap.put("char", Character.TYPE );
       builtInMap.put("byte", Byte.TYPE );
       builtInMap.put("void", Void.TYPE );
       builtInMap.put("short", Short.TYPE );
}

Das heißt, eine Karte erstellen, in dem die Primitive Typen gespeichert werden und wenn die Beschreibung zu einem primitiven gehört dann die abgebildete Klasse. Diese Karte auch von einer externen Konfigurationsdatei geladen werden kann, Flexibilität hinzuzufügen, so dass Sie in statt java.lang.String String als gebaut hinzuzufügen oder potentiell Verfahren wie diese haben.

"doSomething Zeichenfolge yes | no"

Es gibt viele diese Art von Code in OS Projekten wie Struts, Hibernate, Spring und Apache Libs (um nur einige zu nennen), so müssen Sie von Null nicht starten.

BTW. Ich habe nicht den obigen Code kompilieren, aber ich bin mir ziemlich sicher, dass es mit wenig Änderungen funktioniert mich nicht nach unten stimmt dafür.

Apache Commons Lang hat ClassUtils.getClass(String) , die primitiven Typen unterstützt.

Eine Reihe von Klassenmethoden behandelt nicht Primitiven in einer konsistenten Art und Weise leider. Ein üblicher Weg, um diese in forName ist eine Tabelle zu haben, wie;

private static final Map<String, Class> BUILT_IN_MAP = 
    new ConcurrentHashMap<String, Class>();

static {
    for (Class c : new Class[]{void.class, boolean.class, byte.class, char.class,  
            short.class, int.class, float.class, double.class, long.class})
        BUILT_IN_MAP.put(c.getName(), c);
}

public static Class forName(String name) throws ClassNotFoundException {
    Class c = BUILT_IN_MAP.get(name);
    if (c == null)
        // assumes you have only one class loader!
        BUILT_IN_MAP.put(name, c = Class.forName(name));
    return c;
}

Die folgende Code spricht darüber, wie die Klasse eines primitiven Typs zu erhalten, den Feldname ist bekannt, z.B. in diesem Fall 'sampleInt'.

public class CheckPrimitve {
    public static void main(String[] args) {
        Sample s = new Sample();
        try {
            System.out.println(s.getClass().getField("sampleInt").getType() == int.class); // returns true
            System.out.println(s.getClass().getField("sampleInt").getType().isPrimitive()); // returns true
        } catch (NoSuchFieldException e) {          
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }       
    }
}

class Sample {
    public int sampleInt;
    public Sample() {
        sampleInt = 10;
    }
}

Man kann auch prüfen, ob ein bestimmte Wert primitiv ist oder nicht, indem sie die entsprechende Wrapper-Klasse bekommen oder es ist Feldwert.

    public class CheckPrimitve {
        public static void main(String[] args) {
            int i = 3;
            Object o = i;
            System.out.println(o.getClass().getSimpleName().equals("Integer")); // returns true
            Field[] fields = o.getClass().getFields();
            for(Field field:fields) {
                System.out.println(field.getType()); // returns {int, int, class java.lang.Class, int}
            }
        }
    }

Google Guava bietet com.google.common.primitives.Primitives für diese Art von Sachen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top