确定 Object 是否为基元类型

我有一个 Object[]数组,我试图找到那些原语。我试过使用 Class.isPrimitive(),但似乎我做错了:

int i = 3;
Object o = i;


System.out.println(o.getClass().getName() + ", " +
o.getClass().isPrimitive());

指纹 java.lang.Integer, false

有没有正确的方法或其他选择?

136723 次浏览

Object[]中的类型永远不会是原始的 真的——因为你有引用!这里,i的类型是 int,而 o引用的对象的类型是 Integer(由于自动装箱)。

似乎您需要查明该类型是否是“原语的包装器”。我不认为在标准库中有什么内置的东西可以做到这一点,但是它很容易编码:

import java.util.*;


public class Test
{
public static void main(String[] args)
{
System.out.println(isWrapperType(String.class));
System.out.println(isWrapperType(Integer.class));
}


private static final Set<Class<?>> WRAPPER_TYPES = getWrapperTypes();


public static boolean isWrapperType(Class<?> clazz)
{
return WRAPPER_TYPES.contains(clazz);
}


private static Set<Class<?>> getWrapperTypes()
{
Set<Class<?>> ret = new HashSet<Class<?>>();
ret.add(Boolean.class);
ret.add(Character.class);
ret.add(Byte.class);
ret.add(Short.class);
ret.add(Integer.class);
ret.add(Long.class);
ret.add(Float.class);
ret.add(Double.class);
ret.add(Void.class);
return ret;
}
}

Integer不是原语,Class.isPrimitive()不是说谎。

从 Java 1.5开始,有一个新特性叫做自动装箱。编译器自己完成这项工作。当它看到一个机会时,它将原语类型转换为适当的包装类。

这里可能发生的是当你声明

Object o = i;

编译器将编译这个语句

Object o = Integer.valueOf(i);

这是自动装箱。这将解释您正在接收的输出

我认为这是由于 自动装箱

int i = 3;
Object o = i;
o.getClass().getName(); // prints Integer

您可以实现一个实用程序方法,该方法与这些特定的装箱类相匹配,并且如果某个类是原语,则给出该方法。

public static boolean isWrapperType(Class<?> clazz) {
return clazz.equals(Boolean.class) ||
clazz.equals(Integer.class) ||
clazz.equals(Character.class) ||
clazz.equals(Byte.class) ||
clazz.equals(Short.class) ||
clazz.equals(Double.class) ||
clazz.equals(Long.class) ||
clazz.equals(Float.class);
}

你必须处理 Java 的自动装箱。
让我们使用代码 < pre > 公共类测试 { Public static void main (String [] args) { Int i = 3; 对象 o = i; 报税表; } } 您得到了 test.class 类和 Javap-c 测试 javap-c 测试,让您检查生成的字节码 Public 类 test 扩展了 java.lang.Object { 公开测试() ; 密码: 0: aload _ 0 1: invokspecial # 1;//Method java/lang/Object.”: () V 返回

Public static void main (java.lang. String []) ; 密码: 0: iconst _ 3 第1集: istore _ 1 2: iload _ 1 3: invokestatic # 2;//Method java/lang/Integer.valueOf: (I) Ljava/lang/Integer; 6: astore _ 2 7: 返回

} 正如您所看到的,Java 编译器添加了

Invokestatic # 2;//方法 java/lang/Integer.valueOf: (I) Ljava/lang/Integer;
来从 int 中创建一个新的 Integer,然后通过 astore _ 2将 那个新物体存储在 o 中

正如一些人已经说过的,这是由于 自动装箱

您可以创建一个实用程序方法来检查对象的类是否是 IntegerDouble等等。但是有 无法知道对象是否是通过自动装箱原语创建的; 一旦装箱,它看起来就像一个显式创建的对象。

因此,除非您确信您的数组永远不会包含没有自动装箱的包装类,否则就没有真正的解决方案。

这样你就可以看到 isPrimitive 返回 true 是可能的(因为你有足够多的答案告诉你为什么它是 false) :

public class Main
{
public static void main(final String[] argv)
{
final Class clazz;


clazz = int.class;
System.out.println(clazz.isPrimitive());
}
}

当方法接受“ int”而不是“ Integer”时,这在反射中很重要。

这个代码是有效的:

import java.lang.reflect.Method;


public class Main
{
public static void main(final String[] argv)
throws Exception
{
final Method method;


method = Main.class.getDeclaredMethod("foo", int.class);
}


public static void foo(final int x)
{
}
}

此代码失败(找不到方法) :

import java.lang.reflect.Method;


public class Main
{
public static void main(final String[] argv)
throws Exception
{
final Method method;


method = Main.class.getDeclaredMethod("foo", Integer.class);
}


public static void foo(final int x)
{
}
}

基元包装类型将不响应此值。这是用于原语的类表示,不过除了反射之外,我想不出它有多少用途。比如说

System.out.println(Integer.class.isPrimitive());

指纹是“假的”但是

public static void main (String args[]) throws Exception
{
Method m = Junk.class.getMethod( "a",null);
System.out.println( m.getReturnType().isPrimitive());
}


public static int a()
{
return 1;
}

打印“真实”

对于那些喜欢简洁代码的人。

private static final Set<Class> WRAPPER_TYPES = new HashSet(Arrays.asList(
Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class));
public static boolean isWrapperType(Class clazz) {
return WRAPPER_TYPES.contains(clazz);
}

从 Spring 获取 BeanUtils Http://static.springsource.org/spring/docs/3.0.x/javadoc-api/

Apache 变体(commons bean)可能具有类似的功能。

Commons-lang ClassUtils具有相关的 方法

新版本有:

boolean isPrimitiveOrWrapped =
ClassUtils.isPrimitiveOrWrapper(object.getClass());

旧版本有 wrapperToPrimitive(clazz)方法,它将返回 原始通信。

boolean isPrimitiveOrWrapped =
clazz.isPrimitive() || ClassUtils.wrapperToPrimitive(clazz) != null;

Google 的 Guava 库有一个 原始效用,用于检查类是否是原语的包装类型: Primitives.isWrapperType(class)

IsPrimitive ()适用于原语

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


Output:
true
int
int
class java.lang.Class
int

这是我能想到的最简单的方法。包装器类仅在 java.lang包中存在。除了包装类之外,java.lang中没有其他类具有名为 TYPE的字段。您可以使用它来检查一个类是否是 Wrapper 类。

public static boolean isBoxingClass(Class<?> clazz)
{
String pack = clazz.getPackage().getName();
if(!"java.lang".equals(pack))
return false;
try
{
clazz.getField("TYPE");
}
catch (NoSuchFieldException e)
{
return false;
}
return true;
}

我已经迟到了,但是如果你正在测试一个领域,你可以使用 getGenericType:

import static org.junit.Assert.*;


import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;


import org.junit.Test;


public class PrimitiveVsObjectTest {


private static final Collection<String> PRIMITIVE_TYPES =
new HashSet<>(Arrays.asList("byte", "short", "int", "long", "float", "double", "boolean", "char"));


private static boolean isPrimitive(Type type) {
return PRIMITIVE_TYPES.contains(type.getTypeName());
}


public int i1 = 34;
public Integer i2 = 34;


@Test
public void primitive_type() throws NoSuchFieldException, SecurityException {
Field i1Field = PrimitiveVsObjectTest.class.getField("i1");
Type genericType1 = i1Field.getGenericType();
assertEquals("int", genericType1.getTypeName());
assertNotEquals("java.lang.Integer", genericType1.getTypeName());
assertTrue(isPrimitive(genericType1));
}


@Test
public void object_type() throws NoSuchFieldException, SecurityException {
Field i2Field = PrimitiveVsObjectTest.class.getField("i2");
Type genericType2 = i2Field.getGenericType();
assertEquals("java.lang.Integer", genericType2.getTypeName());
assertNotEquals("int", genericType2.getTypeName());
assertFalse(isPrimitive(genericType2));
}
}

甲骨文文件列出了8种基本类型。

您可以通过下面的语句确定对象是否为包装类型:

***objClass.isAssignableFrom(Number.class);***

还可以使用 isPrimitive ()方法确定一个基元对象

public static boolean isValidType(Class<?> retType)
{
if (retType.isPrimitive() && retType != void.class) return true;
if (Number.class.isAssignableFrom(retType)) return true;
if (AbstractCode.class.isAssignableFrom(retType)) return true;
if (Boolean.class == retType) return true;
if (Character.class == retType) return true;
if (String.class == retType) return true;
if (Date.class.isAssignableFrom(retType)) return true;
if (byte[].class.isAssignableFrom(retType)) return true;
if (Enum.class.isAssignableFrom(retType)) return true;
return false;
}

对于 Javapoet的用户,还有一种方法:

private boolean isBoxedPrimitive(Class<?> type) {
return TypeName.get(type).isBoxedPrimitive();
}