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

And*_*erg 7 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;
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ate 6

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

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

您应该传递一个实例MessageInfo作为参数.

你是在MessageInfo课堂上叫这个吗?(为什么?!?)或子类MessageInfo?(试图创建一个超类的私有字段就好像它受到保护一样?有MessageInfo没有getLevel()方法?如果是这样,你可以调用super.getLevel()获取值而不是这样尝试.)

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

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


Tom*_*ine 5

setAccessible被记录为抛出一个SecurityException. 请注意,文档给出了SecurityException即使不SecurityManager存在也会抛出的情况。当然也有可能是因为异步异常: Thread.stop、NIO 缓冲区相关异常或者JVM 错误导致失败。

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