Hein Blöd Hein Blöd - 5 months ago 11
Java Question

Why does accessing a private member of an outer class using reflection throw IllegalAccessException?

Given the code example below, why does

accessUsingReflection
->
theAnswer.get( outer )
throw an
IllegalAccessException
whereas
accessDirectly
prints 42 just fine?

Exception in thread "main" java.lang.IllegalAccessException: Class Outer$Inner can not access a member of class Outer with modifiers "private"


According to this SO answer, I'd expect it to work as the access does happen "(...) from a class that is allowed to access it".

import java.lang.reflect.Field;

public class Outer
{
private int theAnswer = 42;

public static class Inner
{
public void accessDirectly( Outer outer )
{
System.out.println( outer.theAnswer );
}

public void accessUsingReflection( Outer outer ) throws NoSuchFieldException,
SecurityException,
IllegalArgumentException,
IllegalAccessException
{
Field theAnswer = Outer.class.getDeclaredField( "theAnswer" );
// Of course, uncommenting the next line will make the access using reflection work.
// field.setAccessible( true );
System.out.println( theAnswer.get( outer ) );
}
}

public static void main( String[] args ) throws NoSuchFieldException,
SecurityException,
IllegalArgumentException,
IllegalAccessException
{
Outer outer = new Outer();
Inner inner = new Inner();
inner.accessDirectly( outer );
inner.accessUsingReflection( outer );
}
}

Tim Tim
Answer

"Why" questions like these can tricky to answer - there are many layers of "why", including why did the designers choose to do this? what part of the specification allows this? what are the underlying technical details?

I'll answer the last of those, but I'm not sure if that's what you're after.

The Java runtime (JVM, security model, etc) is largely ignorant about inner classes. They are, for the most part, a language issue.

One of the consequences of that is that compiler uses some hidden tricks to allow inner/outer classes to access each other's private members, even though the runtime would not ordinarily allow it.

One of those tricks is that your accessDirectly method is not actually accessing the field directly. The compiler adds a hidden method onto the outer classes that returns the value of theAnswer.

The field (theAnswer) is still private, and as far as the runtime security model is concerned, cannot be accessed outside of the owning (outer) class.

Thus, there are things that you can (seemingly) do in Java code that you can't do with reflection because they rely on special behaviours in the compiler that are not replicated in the reflection library.

You can read more here

Comments