确定对象是否为原始类型


114

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

int i = 3;
Object o = i;

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

版画java.lang.Integer, false

有正确的方法或替代方法吗?


12
简而言之:int.class.isPrimitive()收益率trueInteger.class.isPrimitive()产量false
帕特里克

Answers:


165

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

听起来您需要确定类型是否为“原始包装”。我认为标准库中没有内置任何内容,但是编写起来很容易:

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

我的印象是,它确实适用于原始包装,但java.lang.<type>.TYPE毕竟仅适用于原始包装本身。似乎我无法避免避免单独检查每种类型,这要感谢出色的解决方案。
09年

3
我想知道使用HashSet的开销是否真的比一些if语句好。
NateS

9
@NateS:我认为它更具可读性,这就是为什么我会继续使用它而不是“ if”语句,直到证明该集合的开销是一个实际的瓶颈。
乔恩·斯基特

1
@mark:那是一个非常具体的上下文,应该这样处理。自动装箱适用于枚举吗?不,它们已经是引用类型。它们是不可为空的吗?不,因为它们是引用类型,所以清单还在继续。称它们为原语会极大地削弱该术语的含义,我认为它没有任何好处。
乔恩·斯基特

2
@NateS HashSet允许在O(1)中进行访问,而在最坏的情况下,一行if语句或一条switch语句需要O(包装数)。在实践中,if对于固定数量的9个包装程序而言,语句是否可能毕竟不比基于散列的访问更快。
Karl Richter 2015年

83

commons-lang ClassUtils有相关方法

新版本具有:

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

旧版本具有wrapperToPrimitive(clazz)方法,该方法将返回原始对应关系。

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

1
直到v3.1添加此功能,您的链接反映了2.5 API。我已经改正了。
javamonkey79 2012年

8
Spring还具有ClassUtils类,因此,如果您已经在使用Spring,它将更加方便。
谢尔盖2014年


16

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

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

1
为什么是Void.class?您如何包装空隙?
Shervin Asgari 2011年

2
@Shervin void.class.isPrimitive()返回true
assylias'Aug

1
Void为空,并且a的唯一有效值Voidnull;)对于创建一个Callable<Void>不返回任何内容的Callable 很有用。
彼得·劳瑞

8

从Java 1.5及更高版本开始,有一个称为自动装箱的新功能。编译器自己执行此操作。当发现机会时,它将原始类型转换为适当的包装器类。

当您声明时,这里可能发生的事情

Object o = i;

编译器将编译此语句为:

Object o = Integer.valueOf(i);

这是自动装箱。这将解释您收到的输出。Java 1.5规范的本页详细说明了自动装箱。


6
并非完全正确。它不是新的Integer,而是调用Integer.valueOf(int)来对Integer实例进行一些缓存。
Steve Kuo

1
@SteveKuo Integer.valueOf(int)本身仅在参数为“字节”时返回缓存的值(读取:-128、127 之间,包括两端)。否则调用new Integer(int)。参见:developer.classpath.org/doc/java/lang/…、hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/…
Dragas

6

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


6

我认为这是由于自动装箱而发生的。

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

我最喜欢这个答案,因为它应该比哈希查找更快。内存中的HashSet也少了一个(当然,可能还不多)。最后,人们可以通过排序被认为更频繁的课程来进一步优化这一点。在每个应用程序中情况都会有所不同。
bmauter 2014年

5
您可以安全地更改.equals==。类是单例。
Boann 2014年

5

您必须处理Java的自动装箱。
让我们看一下代码

公开课测试
{
    公共静态void main(String [] args)
    {
        INT我= 3;
        对象o = i;
        返回;
    }
}
得到类test.class和javap -c test,让我们检查生成的字节码。
从“ test.java”编译
公共类测试扩展了java.lang.Object {
公共测试();
  码:
   0:加载_0
   1:调用特殊#1; //方法java / lang / Object。“” :()V
   4:返回

公共静态void main(java.lang.String []); 码: 0:iconst_3 1:istore_1 2:iload_1 3:invokestatic#2;//方法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 将新的Object存储在o中


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

3

就像这样,您可以看到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)
    {
    }
}

2

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

可以创建一个实用程序方法来检查对象的类是否为IntegerDouble等等。但是无法知道是否通过对原语进行自动装箱来创建对象。装箱后,看起来就像是明确创建的对象。

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


2

原始包装器类型将不响应该值。这是用于基元的类表示,尽管除了反射之外,我不能认为它有太多的用途。因此,例如

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

打印“ false”,但是

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

打印“ true”


2

我来晚了,但是如果要测试一个领域,可以使用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种原始类型。


1

这是我能想到的最简单的方法。包装器类仅存在于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;        
}

1
我同意。但是到目前为止,这是我能想到的最简单的方法。:)
Rahul Bobhate


1

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

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

而且您还可以使用isPrimitive()方法确定原始对象


0
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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.