53

我需要在 Java 中进行一些反射方法调用。这些调用将包括具有原始类型(int、double 等)参数的方法。反射性查找方法时指定此类类型的方法是 int.class、double.class 等。

挑战在于我正在接受来自外部源的输入,该输入将动态指定类型。因此,我还需要动态地提出这些类引用。想象一个带有参数类型列表的方法名称列表的分隔文件:

doSomething int double
doSomethingElse java.lang.String boolean

如果输入类似于java.lang.String,我知道我可以使用Class.forName("java.lang.String")该 Class 实例返回。有什么方法可以使用该方法或其他方法来获取原始类型 Classes 吗?

编辑: 感谢所有受访者。很明显,没有内置的方法可以干净地做我想做的事,所以我将满足于重用ClassUtilsSpring 框架中的类。它似乎包含 Class.forName() 的替代品,可以满足我的要求。

4

8 回答 8

31

正如您所说,使用 eg 可以获得原始类型的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
于 2008-10-07T20:02:24.593 回答
21

Spring 框架包含一个实用程序类ClassUtils,其中包含静态方法 forName。此方法可用于您描述的确切目的。

如果您不喜欢依赖 Spring:可以找到该方法的源代码e. G。他们的公共存储库中。类源代码在 Apache 2.0 模型下获得许可。

但是请注意,该算法使用原始类型的硬编码映射。


编辑:感谢评论者 Dávid Horváth 和 Patrick 指出断开的链接。

于 2008-10-07T20:12:30.127 回答
20

可能您只需要映射原语,其余类执行“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 字符串是|否”

在 Struts、Hibernate、Spring 和 Apache libs 等 OS 项目中有大量此类代码(仅举几例),因此您无需从零开始。

顺便提一句。我没有编译上面的代码,但我很确定它只需稍加修改就可以工作,不要对此投反对票。

于 2008-10-07T21:18:27.683 回答
5

Apache Commons LangClassUtils.getClass(String),它支持原始类型。

于 2013-06-25T08:06:35.093 回答
3

不幸的是,许多 Class 方法不能以一致的方式处理原语。在 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;
}
于 2009-03-14T21:10:13.907 回答
2

下面的代码讨论了如何获取字段名称已知的原始类型的类,例如在本例中为“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}
            }
        }
    }
于 2012-10-01T06:26:13.967 回答
1

Google Guava 提供com.google.common.primitives.Primitives这类东西。

于 2017-03-08T14:05:51.883 回答
0

您可以使用此代码:)

/**
 * Get an array class of the given class.
 *
 * @param klass to get an array class of
 * @param <C>   the targeted class
 * @return an array class of the given class
 */
public static <C> Class<C[]> arrayClass(Class<C> klass) {
    return (Class<C[]>) Array.newInstance(klass, 0).getClass();
}

/**
 * Get the class that extends {@link Object} that represent the given class.
 *
 * @param klass to get the object class of
 * @return the class that extends Object class and represent the given class
 */
public static Class<?> objectiveClass(Class<?> klass) {
    Class<?> component = klass.getComponentType();
    if (component != null) {
        if (component.isPrimitive() || component.isArray())
            return Reflect.arrayClass(Reflect.objectiveClass(component));
    } else if (klass.isPrimitive()) {
        if (klass == char.class)
            return Character.class;
        if (klass == int.class)
            return Integer.class;
        if (klass == boolean.class)
            return Boolean.class;
        if (klass == byte.class)
            return Byte.class;
        if (klass == double.class)
            return Double.class;
        if (klass == float.class)
            return Float.class;
        if (klass == long.class)
            return Long.class;
        if (klass == short.class)
            return Short.class;
    }

    return klass;
}

/**
 * Get the class that don't extends {@link Object} from the given class.
 *
 * @param klass to get the non-object class of
 * @return the non-object class of the given class
 * @throws IllegalArgumentException when the given class don't have a primitive type
 */
public static Class<?> primitiveClass(Class<?> klass) {
    if (klass == Character.class)
        return char.class;
    if (klass == Integer.class)
        return int.class;
    if (klass == Boolean.class)
        return boolean.class;
    if (klass == Byte.class)
        return byte.class;
    if (klass == Double.class)
        return double.class;
    if (klass == Float.class)
        return float.class;
    if (klass == Long.class)
        return long.class;
    if (klass == Short.class)
        return short.class;

    throw new IllegalArgumentException(klass + " don't have a primitive type");
}
于 2019-11-25T19:32:46.483 回答