[英]Dynamically find the class that represents a primitive Java type
我需要在 Java 中进行一些反射方法调用。 这些调用将包括具有原始类型(int、double 等)参数的方法。 反射式查找方法时指定此类类型的方法是 int.class、double.class 等。
挑战在于我正在接受来自外部来源的输入,该输入将动态指定类型。 因此,我还需要动态地提出这些类引用。 想象一个带参数类型列表的方法名称列表的分隔文件:
doSomething int double
doSomethingElse java.lang.String boolean
如果输入类似于java.lang.String
,我知道我可以使用Class.forName("java.lang.String")
返回该 Class 实例。 有什么方法可以使用该方法或其他方法来获取原始类型类?
编辑:感谢所有受访者。 很明显,没有内置的方法可以干净利落地做我想做的事情,所以我将满足于重用 Spring 框架中的ClassUtils
类。 它似乎包含 Class.forName() 的替代品,可以满足我的要求。
原始类型的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
Spring 框架包含一个实用程序类ClassUtils ,其中包含用于Name的静态方法。 此方法可用于您描述的确切目的。
如果你不喜欢有Spring的依赖性:该方法的源代码,可以发现如在这里对他们的公共仓库。 类源代码在 Apache 2.0 模型下获得许可。
但是请注意,该算法使用原始类型的硬编码映射。
编辑:感谢评论者 Dávid Horváth 和 Patrick 指出断开的链接。
可能您只需要映射原语,其余类执行“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 项目中有很多此类代码,因此您无需从零开始。
顺便提一句。 我没有编译上面的代码,但我很确定它只需稍作修改就可以工作,不要为此投票给我。
不幸的是,许多 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;
}
以下代码讨论了如何获取字段名称已知的原始类型的类,例如在本例中为“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}
}
}
}
Google Guava 为这类东西提供了com.google.common.primitives.Primitives
。
您可以使用此代码:)
/**
* 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");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.