【问题标题】:IllegalArgumentException: the error message does not make senseIllegalArgumentException:错误信息没有意义
【发布时间】:2011-07-14 13:32:01
【问题描述】:

我正在尝试调试依赖反射的 Java 应用程序。现在我得到的错误如下:

java.lang.IllegalArgumentException: Can not set int field DataStructures.StackAr.topOfStack to java.lang.Integer
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37)
    at sun.reflect.UnsafeIntegerFieldAccessorImpl.getInt(UnsafeIntegerFieldAccessorImpl.java:38)
    at sun.reflect.UnsafeIntegerFieldAccessorImpl.get(UnsafeIntegerFieldAccessorImpl.java:18)
    at java.lang.reflect.Field.get(Field.java:358)

应用程序运行的最后几行是:

Field f = classUnderTest.getDeclaredField(processFieldName(var));
f.setAccessible(true);
Long value = (Long) f.get(runtimeInstance);

错误消息有点误导,我不确定为什么它提到set 操作,而我正在尝试执行get

我怀疑runtimeInstance 不是预期类的对象。但是那个错误消息让我失望了。

以前有人遇到过这个问题吗?有什么线索吗?

PS1:导致异常的确切行是这一行:

Long value = (Long) f.get(runtimeInstance);

PS2:processFieldName(var) 处理字段的正确名称,即它从字段名称为 this. 等的字符串中删除一些伪像。

【问题讨论】:

  • 这可能是一个自动装箱问题,即 int 自动被 Integer 包裹。
  • (1) 检查究竟是哪一行产生了错误。你写了3行。 (2) processFieldName(var) 返回什么? (3)它与classUnderTest中的字段如何对应?
  • 到底是什么样的字段?
  • 我同意你对 runtimeInstance 的怀疑。你为什么不测试一下?
  • 试过在eclipse上使用调试器吗?

标签: java reflection


【解决方案1】:

从这些访问器的来源看来,声明该字段的类似乎不能从 runtimeInstance 的类中分配:

如果 (!(this.field.getDeclaringClass().isAssignableFrom(paramObject.getClass())))
  throwSetIllegalArgumentException(paramObject);

field 似乎是您想从实例中获取的字段,paramObject 是您的 runtimeInstance

因此,如果该字段的声明类不是 paramObject 的类或超类,您将收到该消息。

您的paramObject 是否有可能是Integer

编辑:这里有一些来自 OpenJDK 的源代码(应该类似于 Oracle 的),用于解释消息:

  protected String getSetMessage(String attemptedType, String attemptedValue) {
         String err = "Can not set";
         if (Modifier.isStatic(field.getModifiers()))
             err += " static";
         if (isFinal)
             err += " final";
         err += " " + field.getType().getName() + " field " + getQualifiedFieldName() + " to ";
         if (attemptedValue.length() > 0) {
             err += "(" + attemptedType + ")" + attemptedValue;
         } else {
             if (attemptedType.length() > 0)
                 err += attemptedType;
             else
                 err += "null value";
         }
         return err;
     }

收到您的消息java.lang.IllegalArgumentException: Can not set int field DataStructures.StackAr.topOfStack to java.lang.Integer,我们发现:

  • 该字段的类型为int
  • 该字段的名称是topOfStack 在类DataStructures.StackAr
  • attemptedTypejava.lang.Integer

由于attemptedType 是您的runtimeInstance 的类型,我怀疑classUnderTestDataStructures.StackArruntimeInstance 的类型是java.lang.Integer

【讨论】:

  • 一个非常完整的答案,谢谢。我会走那条路,我有一个怀疑,但错误信息不够清楚。
【解决方案2】:

您在堆栈顶部得到的错误的 java 源代码似乎表明 runtimeInstance 与 classUnderTest 不是同一个类:

protected void ensureObj(Object o) {
                 // NOTE: will throw NullPointerException, as specified, if o is null
                if (!field.getDeclaringClass().isAssignableFrom(o.getClass())) {
                     throwSetIllegalArgumentException(o);
                 }
             }

【讨论】:

  • @user102008 但是,当onull 时,它不会抛出NullPointerException。正如评论所示,这是故意的。除此之外,建议对引用的代码进行改进是没有意义的。
【解决方案3】:

仔细阅读错误信息:“Can not set int field DataStructures.StackAr.topOfStack to java.lang.Integer

您需要在分配之前将Integer 更改为int

【讨论】:

  • 我不认为我理解你的建议。我不想分配任何东西。我只是想获得价值。
  • @rossum 但他在哪里尝试使用整数?
  • JVM 显然看到他使用的是整数,否则它不会发出该错误消息。我需要查看详细的类声明来判断哪个特定字段被声明为Integer
  • 我很确定,你错了。 java.lang.Field.getObjectset 的文档明确允许(取消)包装。如果我理解接受的答案,那就是混淆对象及其字段。
猜你喜欢
  • 2021-09-09
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
  • 2017-01-04
  • 1970-01-01
  • 1970-01-01
  • 2018-08-02
  • 1970-01-01
相关资源
最近更新 更多