我有一段代码需要在方法中传递字段的类。由于我的代码的机制,我只能处理引用对象而不是基元。我想要一种简单的方法来确定Field
的类型是否是原始的,并将其与适当的包装类交换。所以在代码中我到目前为止所做的是这样的:
Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType();
if (c == int.class) {
c = Integer.class;
}
else if (c == float.class) {
c = Float.class;
}
// etc
myMethod(c);
这很好用,除了我需要显式检查所有基本类型并用适当的包装类交换它们。现在我知道没有那么多的原始类型,简单地列出它们就不会有问题,但我想知道是否有更简单,更优雅的方式。
答案 0 :(得分:37)
我在回答中使用了Google Collections Library,因为我已经被宠坏了,但是如果你愿意的话,你可以看看如何使用简单的HashMaps来实现它。
// safe because both Long.class and long.class are of type Class<Long>
@SuppressWarnings("unchecked")
private static <T> Class<T> wrap(Class<T> c) {
return c.isPrimitive() ? (Class<T>) PRIMITIVES_TO_WRAPPERS.get(c) : c;
}
private static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS
= new ImmutableMap.Builder<Class<?>, Class<?>>()
.put(boolean.class, Boolean.class)
.put(byte.class, Byte.class)
.put(char.class, Character.class)
.put(double.class, Double.class)
.put(float.class, Float.class)
.put(int.class, Integer.class)
.put(long.class, Long.class)
.put(short.class, Short.class)
.put(void.class, Void.class)
.build();
奇怪的是,JDK中没有任何内容存在,但实际上没有任何内容。
编辑:我完全忘记了我们发布了这个:
http://google.github.io/guava/releases/21.0/api/docs/com/google/common/primitives/Primitives.html
它有wrap()方法,加上unwrap()和其他一些附带的东西。
答案 1 :(得分:37)
Apache Commons Lang有一个实用方法来执行此操作(ClassUtils.primitiveToWrapper()),这将是一个丑陋的掩护,但至少你可以假装它很好。
答案 2 :(得分:9)
如果您不需要高度优化的代码,这是另一种方式:
Class<?> primitive=long.class;
Class<?> boxed=Array.get(Array.newInstance(primitive,1),0).getClass();
System.out.println(primitive.getName());
System.out.println(boxed.getName());
(编辑/添加说明)
首先,看看Java是否有一个方法在给定基本类型时为您提供包装类。无法找到任何。
然后,看看你是否可以在给出一个原始类型时让Java创建一个原始值(然后你可以以某种方式从中获取一个对象)。无法找到办法。
但后来发现,当给定基本类型时,您可以让Java创建一个原始值数组。然后有一个Java方法,它为您提供数组元素的包装类型的对象(它是原始的)。获得该对象后,即可获得该类型。
所以这就是整个过程的工作原理:
方法Array.newInstance()创建一个您指定的任何类型的数组,无论它是基元还是对象。在object的情况下,所有元素都是对象类型,但初始化为null。在原始的情况下,元素是原始类型。但是原始变量/数组元素不能为空,因此它们具有基本类型的默认值,例如, int将为零。因此,没有元素将为null。现在,如果你试图通过使用Array.get()来获取元素的值,那么Array.get()除了选择对象的原始值之外别无选择,例如int到Integer,因为Array.get()不能返回原始值。现在你有一个原始基本类型的装箱(包装)类型的对象。最后,调用Object.getClass()会给你装箱(包装)类型。
这个技巧适用于当今和未来Java中的任何原始类型。
答案 3 :(得分:7)
您可以调用class.isPrimitive()来了解它是否是原语,但是,没有装箱方法来转换JDK中的类。至少有一个open bug与此相关。
答案 4 :(得分:2)
(想法)获取类名并制作首字母大写,然后调用Class.forInstance(className).newInstance(primitive)。例外情况是&#34; char&#34; - &GT;角色和&#34; int&#34; - &GT;整数
Class c=Primitive class object
if (c.isPrimitive()) {
if (c == char.class) {
Object wrapper=new Character(primitive var);
}
if (c == int.class) {
Object wrapper=new Integer(primitive var);
}
else {
String name=c.getName();
try {
Class<?> c2=Class.forName("java.lang."+name.substring(0,1).toUpperCase()+name.substring(1,name.length()));
Object wrapper=c2.getConstructor(c).newInstance(primitve_var);
} catch (ClassNotFoundException ex) {
System.out.println("RROR");
}
}
}
答案 5 :(得分:2)
Class<?> toWrapper(Class<?> clazz) {
if (!clazz.isPrimitive())
return clazz;
if (clazz == Integer.TYPE)
return Integer.class;
if (clazz == Long.TYPE)
return Long.class;
if (clazz == Boolean.TYPE)
return Boolean.class;
if (clazz == Byte.TYPE)
return Byte.class;
if (clazz == Character.TYPE)
return Character.class;
if (clazz == Float.TYPE)
return Float.class;
if (clazz == Double.TYPE)
return Double.class;
if (clazz == Short.TYPE)
return Short.class;
if (clazz == Void.TYPE)
return Void.class;
return clazz;
}
答案 6 :(得分:1)
还有com.sun.beans.finder.PrimitiveWrapperMap#getType(primitiveName)。 但是当然不建议使用“com.sun”包中的类......
答案 7 :(得分:0)
我们正在检索一个字段,然后发现它包含原始类型。
Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.getType();
但是我们需要包装类型。
现在,您已经发现原始类唯一适合的事情就是为c.isPrimitive();
返回true。
来自wiki books - java programming:
原始类型是Java语言中可用的最基本的数据类型。有8个:boolean,byte,char,short,int,long,float和double。这些类型充当Java中数据处理的基础。这些类型仅用于一个目的-包含一种纯净的简单值。
尝试以其他方式使用它们,您会遭受很多伤害。
Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.newInstance();
// java.lang.InstantiationException thrown: int
// at Class.newInstance (Class.java:545)
Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(0);
// java.lang.ClassCastException thrown: Cannot cast java.lang.Integer to int
// at Class.cast (Class.java:3578)
Field f = getTheField();
Class<?> c = f.getType();
Object wrapper = c.cast(null);
没有例外,变量wrapper
的类型为class java.lang.Integer
,但其值为null
,可以为我们带来很多好处。
boolean isSuperClass = Integer.class.isAssignableFrom(int.class); // false
这显然不能使我们走到任何地方,而应该退后一步,看看更大的情况。
回顾一下:自java.lang.reflect.Field
被标记为final以来,我们一直在检索必须来自某个地方的字段,并且不公开任何公共构造函数。
如果我们要填补空白,它可能看起来像这样。
public class Simple {
public static int field;
public static void main(String[] args) {
Field f = Simple.class.getField("field"); // Actual method that returns my Field
Class<?> c = f.getType();
}
}
与其与机器抗争,不如让它一起工作。基元的好处之一是它们将初始化为默认值0
而不是null
。让我们看看是否可以使用它。
public class Simple {
public static int field;
public static void main(String[] args) {
Simple boxer = new Simple();
Field f = Simple.class.getField("field");
Object wrapped = f.get(null); // Integer value 0
Class<?> c = wrapped.getClass(); // class java.lang.Integer
}
}
这比以前容易得多,我们甚至不需要做任何事情,一切都为我们完成了。另一个不愿意与潮流背道而驰的好处。
让我们对此加以改进,重构并通过提取一种方法使其更可重用。
public class Simple {
public static int field;
public static <T> T wrap(T t) {
return t;
}
public static void main(String[] args) {
Field f = Simple.class.getField("field");
Class<?> c = Simple.wrap(f.get(null)).getClass(); // class java.lang.Integer
}
}
一个简单的原始包装,而不必查看类型或使用查找表,因为Java已经可以做到了。
Field f = getTheField(); // Dummy method that returns my Field
Class<?> c = f.get(null).getClass();
或者如果该字段不是静态的,则可以用实例替换null。
nJoy!
答案 8 :(得分:0)
使用最新的jdk,现在这是一个单行代码:
@SuppressWarnings("unchecked")
public static <T> Class<T> wrap(Class<T> c) {
return (Class<T>) MethodType.methodType(c).wrap().returnType();
}
@SuppressWarnings("unchecked")
public static <T> Class<T> unwrap(Class<T> c) {
return (Class<T>) MethodType.methodType(c).unwrap().returnType();
}
Here是我使用JMH
编写的测试,结果如下:
Benchmark Mode Cnt Score Error Units
PrimitiveToWrapper.ifStatements avgt 30 42.112 ± 0.716 ns/op
PrimitiveToWrapper.map avgt 30 45.018 ± 0.923 ns/op
PrimitiveToWrapper.wrap avgt 30 52.369 ± 0.836 ns/op
差别很小。