在什么情况下Java的field.setAccessible(true)会失败?

时间:2009-10-11 03:51:54

标签: java reflection

我的情况是用户的代码在反射访问的字段上抛出IllegalAccessException。在访问该字段之前,会调用setAccessible(true)。所以,在我看来,这种方法是默默失败的。

在什么情况下会发生这种情况?这可能与安全经理有关吗?

以下是导致异常的代码段:

private static Field levelField;
public int getLevel() {
    try {
        if (levelField == null) {
            levelField = MessageInfo.class.getDeclaredField("level");
            levelField.setAccessible(true);
        }
        return levelField.getInt(this);  // <-- IllegalAccessException thrown here
    } catch (Exception e) {
         handleException(e);
    }
    return ICompilationUnit.NO_AST;
}

3 个答案:

答案 0 :(得分:6)

它不应该是安全管理器问题 - 您将获得SecurityException或子类。

代码levelField.getInt(*this*)看起来不正确......

您应该传递MessageInfo的实例作为参数。

你是在MessageInfo班级内打电话吗? (为什么?!?)或MessageInfo的子类? (尝试创建一个超类的私有字段就好像它受到保护一样?MessageInfogetLevel()方法吗?如果有,你可以调用super.getLevel()来获取值而不是尝试它这样。)

如果它不是MessageInfo或子类,那就是你的问题 - 你有level类的MessageInfo字段,并且你试图从该字段中获取该字段的值现在的课程。虽然这应该是IllegalArgumentExeception而不是IllegalAccessException ...

如果它确实是'IllegalAccessExeception' - 尝试在if (levelField == null)块中放入一些日志记录 - 确保它真的被执行了。该字段是静态的 - 可能有一些其他实例或方法在其上设置值。

答案 1 :(得分:4)

记录

setAccessible以抛出SecurityException。请注意,文档提供了即使没有SecurityException也会引发SecurityManager的情况。当然,它也可能由于异步异常而失败:Thread.stop,NIO缓冲区相关异常或JVM错误。

此代码的真正问题(除了使用反射之外)是有一个字段可以设置为部分初始化。这会导致竞争条件(你有一个可变的静态,因此你需要担心线程(提示,避免可变静态!))。在调用getInt之前,另一个主题可能会在Field上调用setAccessible。正如原始提问者似乎已经发现的那样,它也不例外。在静态初始化器中设置字段会更安全,更清晰。

答案 2 :(得分:0)

来自Java自己的setAccessible() IllegalAccessException.

  

如果flag为true,则引发SecurityException,但不能更改输入数组的任何元素的可访问性(例如,如果元素对象是类Class的Constructor对象)。在出现这种SecurityException的情况下,对象的可访问性被设置为对数组元素进行标记,直到(和排除)发生异常的元素;超出(和包括)发生异常的元素的元素的可访问性不变。

不幸的是,他们没有提及{{1}}

的任何内容