【问题标题】:Determining if an Object is of primitive type确定对象是否为原始类型
【发布时间】:2009-04-02 14:36:28
【问题描述】:

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

int i = 3;
Object o = i;

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

打印java.lang.Integer, false

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

【问题讨论】:

  • 简而言之:int.class.isPrimitive() 产生trueInteger.class.isPrimitive() 产生 false

标签: java reflection


【解决方案1】:

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

【讨论】:

  • 我的印象是它确实适用于原始包装器,但它毕竟只适用于java.lang.&lt;type&gt;.TYPE,这当然是原始包装器本身。看来我无法避免单独检查每种类型,谢谢你的好解决方案。
  • 我想知道使用 HashSet 的开销是否真的比一些 if 语句更好。
  • @NateS:我相信它更具可读性,这就是为什么我会使用它而不是“if”语句,直到它证明集合的开销是一个实际的瓶颈。
  • @mark:那么这是一个非常具体的上下文,应该这样对待。自动装箱是否适用于枚举?不,它们已经是引用类型。它们是不可为空的吗?不,因为它们是引用类型……不胜枚举。将它们称为原语会极大地削弱该术语的含义,而且我认为它没有任何好处。
  • @NateS HashSet 允许在 O(1) 中访问,而在最坏的情况下,一行 if 语句或 switch 语句需要 O(# of wrappers)。在实践中,如果if 用于固定数量的 9 个包装器的语句可能并不比基于哈希的访问快,这是值得怀疑的。
【解决方案2】:

commons-langClassUtils 有相关的方法

新版本有:

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

旧版本有wrapperToPrimitive(clazz) 方法,会返回primitive 对应关系。

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

【讨论】:

  • 这不是added until v3.1,您的链接反映了 2.5 API。我已经更正了。
  • Spring 也有ClassUtils 类,所以如果你已经在使用 Spring 会更方便。
  • @Bozho ClassUtils.isPrimitiveOrWrapper 为 java.lang.String 提供错误
  • @Joy,String 既不是原始数据也不是包装原始数据,请参阅here 了解所有原始数据类型的概述。如果您需要,当然可以将object instanceof String 添加到您的代码中!
【解决方案3】:

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

Class.isPrimitive() 适用于原语

【讨论】:

  • someObject.getClass().isPrimitive()
【解决方案4】:

适合那些喜欢简洁代码的人。

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

【讨论】:

  • 为什么选择 Void.class?你如何包装一个空白?
  • @Shervin void.class.isPrimitive() 返回真
【解决方案5】:

从 Java 1.5 及更高版本开始,有一个称为自动装箱的新功能。编译器自己做这件事。当它看到机会时,它会将原始类型转换为其适当的包装类。

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

Object o = i;

编译器会把这条语句编译成这样说的

Object o = Integer.valueOf(i);

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

【讨论】:

【解决方案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(当然这可能不多)。最后,人们可以通过对那些被认为更频繁的类进行排序来进一步优化这一点。这在每个应用程序中都会有所不同。
  • 您可以安全地将.equals 更改为==。类是单例的。
【解决方案7】:

Integer 不是原始人,Class.isPrimitive() 没有说谎。

【讨论】:

    【解决方案8】:
    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】:

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

      公开课测试
      {
          公共静态无效主要(字符串[]参数)
          {
              诠释 i = 3;
              对象 o = i;
              返回;
          }
      }
      你得到类 test.class 和 javap -c test 让你检查生成的字节码。
      从“test.java”编译
      公共类测试扩展 java.lang.Object{
      公共测试();
        代码:
         0:aload_0
         1:调用特殊#1; //方法 java/lang/Object."":()V
         4:返回
      
      

      public static void main(java.lang.String[]); 代码: 0:iconst_3 1:istore_1 2:iload_1 3:调用静态#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 中

      【讨论】:

        【解决方案10】:

        你可以看到 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)
            {
            }
        }
        

        【讨论】:

          【解决方案11】:

          正如一些人已经说过的,这是由于autoboxing

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

          所以除非你确定你的数组在没有自动装箱的情况下永远不会包含包装类,否则没有真正的解决方案。

          【讨论】:

            【解决方案12】:

            原始包装器类型不会响应此值。这是用于基元的类表示,尽管除了反射之外,我想不出它有太多用途。所以,例如

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

            打印“真”

            【讨论】:

              【解决方案13】:

              我来晚了,但如果你正在测试一个领域,你可以使用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 种基本类型。

              【讨论】:

                【解决方案14】:

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

                【讨论】:

                • 我同意。但到目前为止,这是我能想到的最简单的方法。 :)
                【解决方案15】:

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

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

                【讨论】:

                  【解决方案16】:

                  你可以通过下面的语句来确定一个对象是否是包装器类型:

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

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

                  【讨论】:

                    【解决方案17】:
                    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
                    

                    【讨论】:

                      【解决方案18】:

                      javapoet的用户,也有这种方式:

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

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2015-12-09
                        • 2011-08-21
                        • 2022-07-23
                        • 2013-01-12
                        • 1970-01-01
                        • 2011-01-27
                        相关资源
                        最近更新 更多