【问题标题】:Java Reflection calling constructor with primitive types具有原始类型的 Java 反射调用构造函数
【发布时间】:2010-10-13 15:56:52
【问题描述】:

我的测试框架中有一个方法可以创建一个类的实例,具体取决于传入的参数:

public void test(Object... constructorArgs) throws Exception {
    Constructor<T> con;
    if (constructorArgs.length > 0) {
        Class<?>[] parameterTypes = new Class<?>[constructorArgs.length];
        for (int i = 0; i < constructorArgs.length; i++) {
            parameterTypes[i] = constructorArgs[i].getClass();  
        }
        con = clazz.getConstructor(parameterTypes);
    } else {
        con = clazz.getConstructor();
    }
}

问题是,如果构造函数有原始类型,这不起作用,如下:

public Range(String name, int lowerBound, int upperBound) { ... }

.test("a", 1, 3);

结果:

java.lang.NoSuchMethodException: Range.<init>(java.lang.String, java.lang.Integer, java.lang.Integer)

原始整数被自动装箱到对象版本中,但我如何让它们返回以调用构造函数?

【问题讨论】:

    标签: java reflection


    【解决方案1】:

    使用Integer.TYPE 而不是Integer.class

    根据Javadocs,这是“代表原始类型int 的Class 实例。”

    您也可以使用int.class。这是Integer.TYPE 的快捷方式。不仅是类,即使对于原始类型,您也可以在 Java 中说 type.class

    【讨论】:

    • int.class 是 Integer.TYPE 的快捷方式,对于 Java 中的任何基本类型,您都可以编写:type.class
    • 这应该是一个公认的答案。您在几秒钟内击败了 Plaudit Design ;-) 刚刚编辑以包含 iirekm 的评论。
    【解决方案2】:

    要引用原始类型,例如:

    Integer.TYPE;
    

    您需要知道传递给您的方法的哪些参数是原始值。你可以这样做:

    object.getClass().isPrimitive()
    

    【讨论】:

      【解决方案3】:

      由于原始类型被自动装箱,getConstructor(java.lang.Class&lt;?&gt;... parameterTypes) 调用将失败。您将需要手动遍历可用的构造函数。如果所有类型都匹配,那么你很好。如果某些类型不匹配,但所需类型是原始类型并且可用类型是相应的包装类,那么您可以使用该构造函数。见下文:

      static <C> Constructor<C> getAppropriateConstructor(Class<C> c, Object[] initArgs){
          if(initArgs == null)
              initArgs = new Object[0];
          for(Constructor con : c.getDeclaredConstructors()){
              Class[] types = con.getParameterTypes();
              if(types.length!=initArgs.length)
                  continue;
              boolean match = true;
              for(int i = 0; i < types.length; i++){
                  Class need = types[i], got = initArgs[i].getClass();
                  if(!need.isAssignableFrom(got)){
                      if(need.isPrimitive()){
                          match = (int.class.equals(need) && Integer.class.equals(got))
                          || (long.class.equals(need) && Long.class.equals(got))
                          || (char.class.equals(need) && Character.class.equals(got))
                          || (short.class.equals(need) && Short.class.equals(got))
                          || (boolean.class.equals(need) && Boolean.class.equals(got))
                          || (byte.class.equals(need) && Byte.class.equals(got));
                      }else{
                          match = false;
                      }
                  }
                  if(!match)
                      break;
              }
              if(match)
                  return con;
          }
          throw new IllegalArgumentException("Cannot find an appropriate constructor for class " + c + " and arguments " + Arrays.toString(initArgs));
      }
      

      【讨论】:

        【解决方案4】:

        你可以写

        int[].class.getComponentType()
        

        Integer.TYPE
        

        int.class
        

        【讨论】:

          【解决方案5】:

          如果原始 int 值被自动装箱到 Integer 对象中,则它不再是原始值。在某些时候,您无法从 Integer 实例中判断它是否是 int

          我建议将两个数组传递给test 方法:一个带有类型,另一个带有值。如果您有构造函数 MyClass(Object) 并传递字符串值(getConstructor 将寻找 String 构造函数),它也会消除歧义。
          此外,如果参数值为空,您无法判断预期的参数类型。

          【讨论】:

          • if primitive int value is autoboxed into Integer object, it's not primitive anymore. You can't tell from Integer instance whether it was int at some point 没有得到您提出的问题的这一点。如果一个原语被装箱为整数而不是它为什么不解析为 var args
          • @org.life.java 你是什么意思,“不解析为 var args” ?错误是因为找不到构造函数。 Vararg 部分工作顺利,int 被转换为 Integer 用于 constructorArgs 数组的第二个和第三个元素(原因很简单,int 不能包含 Object[]) 的一部分。
          • 如何将其标记为答案?请参阅下面的“使用Integer.TYPE 而不是Integer.class。”来自@Andrzej Doyle 和其他人
          【解决方案6】:

          要实际检查一个类型是原始类型还是包装器使用:

          ClassUtils.isPrimitiveOrWrapper(memberClazz)
          

          如果您想检查它是否是特定类型,请查看:

          https://stackoverflow.com/a/27400967/2739334

          无论如何@Andrzej Doyle 是完全正确的!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-01-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多