Динамически найти класс, который представляет примитивный тип Java - PullRequest
46 голосов
/ 07 октября 2008

Мне нужно сделать некоторые рефлексивные вызовы методов в Java. Эти вызовы будут включать методы с аргументами примитивных типов (int, double и т. Д.). Способ определения таких типов при рефлексивном поиске метода - int.class, double.class и т. Д.

Проблема в том, что я принимаю входные данные из внешнего источника, который будет определять типы динамически. Поэтому мне нужно динамически создавать эти ссылки на классы. Представьте в файле с разделителями список имен методов со списками типов параметров:

doSomething int double
doSomethingElse java.lang.String boolean

Если бы ввод был чем-то вроде java.lang.String, я знаю, что мог бы использовать Class.forName("java.lang.String") для этого экземпляра класса обратно. Есть ли способ использовать этот метод или другой, чтобы вернуть классы примитивного типа обратно?

Edit: Спасибо всем респондентам. Кажется очевидным, что не существует встроенного способа для чистого выполнения того, что я хочу, поэтому я остановлюсь на повторном использовании класса ClassUtils из среды Spring. Кажется, он содержит замену Class.forName (), которая будет работать с моими требованиями.

Ответы [ 7 ]

26 голосов
/ 08 октября 2008

Экземпляры Class для примитивных типов можно получить, как вы сказали, например, с помощью. int.class, но также можно получить те же значения, используя что-то вроде Integer.TYPE. Каждый класс-оболочка примитивов содержит статическое поле TYPE, которое имеет соответствующий экземпляр примитивного класса.

Вы не можете получить примитивный класс через forName, но вы можете получить его из класса, который легко доступен. Если вам абсолютно необходимо использовать рефлексию, вы можете попробовать что-то вроде этого:

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

intClass.equals(int.class);         // => true
21 голосов
/ 08 октября 2008

Платформа Spring содержит служебный класс ClassUtils , который содержит статический метод forName. Этот метод может использоваться для той цели, которую вы описали.

Если вы не хотите зависеть от Spring: можно найти исходный код метода e. г. здесь в их публичном хранилище. Исходный код класса лицензируется по модели Apache 2.0.

Обратите внимание, что алгоритм использует жестко закодированную карту примитивных типов.


Редактировать: Спасибо комментаторам Давиду Хорвату и Патрику за указание на неработающую ссылку.

17 голосов
/ 08 октября 2008

Вероятно, вам просто нужно отобразить примитивы, а для остальных классов выполнить метод "forName":

Я бы сделал что-то вроде:

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

То есть создайте карту, в которой хранятся типы примитивов, и если описание принадлежит примитиву, тогда используйте отображенный класс. Эта карта также может быть загружена из внешнего файла конфигурации, чтобы добавить гибкости, поэтому вы можете добавить String как встроенную вместо java.lang.String или потенциально иметь такой метод.

"doSomething string yes | no"

Существует много такого рода кода в проектах ОС, таких как библиотеки Struts, Hibernate, Spring и Apache (только некоторые из них), поэтому вам не нужно начинать с нуля.

КСТАТИ. Я не скомпилировал приведенный выше код, но я почти уверен, что он работает с небольшими изменениями, не голосуйте за меня.

5 голосов
/ 25 июня 2013

Apache Commons Lang имеет ClassUtils.getClass (String) , который поддерживает примитивные типы.

3 голосов
/ 15 марта 2009

К сожалению, некоторые методы класса не обрабатывают примитивы согласованным образом. Распространенным способом решения этой проблемы в forName является таблица типа:

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;
}
2 голосов
/ 01 октября 2012

В следующем коде рассказывается, как получить класс примитивного типа, имя поля которого известно, например, в этом случае '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;
    }
}

Можно также проверить, является ли данное значение примитивным или нет, получив соответствующий класс-оболочку или значение его поля.

    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}
            }
        }
    }
1 голос
/ 08 марта 2017

Google Guava предлагает com.google.common.primitives.Primitives для такого рода вещей.

...