确定对象是否是原始类型

时间:2009-04-02 14:36:28

标签: java reflection

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

int i = 3;
Object o = i;

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

打印java.lang.Integer, false

是否有正确的方法或替代方案?

19 个答案:

答案 0 :(得分:155)

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

答案 1 :(得分:72)

commons-lang ClassUtils有相关的方法

新版本有:

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

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

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

答案 2 :(得分:24)

Google的Guava库有一个Primitives实用程序,用于检查类是否是基元的包装类型: http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/primitives/Primitives.html

Primitives.isWrapperType(class)

Class.isPrimitive()适用于基元

答案 3 :(得分: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);
}

答案 4 :(得分:8)

从Java 1.5及更高版本开始,有一项名为auto-boxing的新功能。编译器本身就是这样做的。当它看到机会时,它会将原始类型转换为适当的包装类。

这里可能发生的事情是你宣布

Object o = i;

编译器将编译此语句为

Object o = Integer.valueOf(i);

这是自动拳击。这可以解释您收到的输出。 This page from the Java 1.5 spec explains auto-boxing more in detail.

答案 5 :(得分:6)

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

答案 6 :(得分:5)

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

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

答案 7 :(得分:5)

你必须处理java的自动装箱 让我们拿代码

public class test
{
    public static void main(String [ ] args)
    {
        int i = 3;
        Object o = i;
        return;
    }
}
你得到类test.class和 javap -c test 让你检查生成的字节码。
Compiled from "test.java"
public class test extends java.lang.Object{
public test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public static void main(java.lang.String[]); Code: 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: return

}

正如你可以看到java编译器添加
invokestatic    #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
从int创建一个新的Integer,然后通过astore_2

那个新的Object 存储在o中

答案 8 :(得分: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;
}

答案 9 :(得分:3)

这样你就可以看到isPrimitive可以返回true(因为你有足够的答案显示它为什么是假的):

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

答案 10 :(得分:2)

有几个人已经说过,这是由于autoboxing

可以创建一个实用工具方法来检查对象的类是IntegerDouble等。但是无法知道对象是否是对象是通过自动装箱原语创建的;一旦它被装箱,它就像一个明确创建的对象。

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

答案 11 :(得分: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”

答案 12 :(得分: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));
    }
}

Oracle docs列出了8种基本类型。

答案 13 :(得分:1)

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

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

答案 14 :(得分:1)

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

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

您还可以使用isPrimitive()方法

来确定原始对象

答案 15 :(得分: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;        
}

答案 16 :(得分: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

答案 17 :(得分:0)

十年来,这个问题仍然存在,至少对我来说... 如果“ isPrimitive”不适用于基本类型的实例,那该怎么办?我知道'int.class'是原始的,所以我不需要问这个... 好吧,我做到了:

import java.lang.reflect.*;
class Test{
  public static void main(String[] args) throws Exception{
    char x=3; boolean b=true; int i=2;
    Object o= i;
    Object name =o.getClass().getField("TYPE").get(o);
    System.out.println(""+name);
  }
}

这将返回一个字符串,例如“ int”,“ char”,“ boolean”等。 八个基元都有一个包装类,其中的“ TYPE”字段包含这些值。无效类型也可以。

另一种实用用法:

import java.util.*;
import java.lang.reflect.*;
class Test{
  static void print(Object O){System.out.println(O);}
  public static void main(String[] args) throws Exception{
    List list2 = new ArrayList<Object>(List.of("word",2,3.0f,4.0,(char)65, a)); //where a= any user class instance. 
//And see like this list simulates a tuple like in Pyhton, another lack i see in Java.
//But indeed, this kind of List<Object> is still better then a immutable tuple. 
//And this was another of my doubts (tuples), and of other's people, as i've seen in my searchs at web.
    ver(list2);

  }
  static void ver(List lis){
    List prims = new ArrayList<String>(List.of("Boolean","Character","Byte","Double","Float","Integer","Long","Short"));
    for(Object o: lis){
      String s=o.getClass().getSimpleName();
      print((prims.contains(s)?"Yes":"No"));
    }
  }

输出: 没有 是 是 是 是 不

答案 18 :(得分:0)

对于javapoet的用户,也可以这样:

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