Reputation: 7294
Recently I've faced a problem getting a runtime error java.lang.IllegalAccessError
when trying to access from inner class a protected field declared in outer's parent class that was loaded by a different class loader. Briefly:
Parent
has protected field p
.Outer
extends Parent
.Inner
is an inner class defined in class Outer
.Inner
class there's a code: Outer.this.p
.Normally it's compiled and runs fine until Parent
and Outer
class are loaded by different class loaders. In this case we get java.lang.IllegalAccessError
when trying to access Outer.this.p
from Inner
.
I found an old bug report (which appeared to be a feature) describing this behavior:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6258289
But resolution sounds contradictive to me:
The key is that in the failing case the inner class isn't in the same package (and isn't a subclass of) ConcreteCommand/AbstractCommand. This is simply a violation of the Java specification for protected classes.
It sounds correct. But if we declare Parent
and Outer
classes in different packages but load with the single class loader (simply create sample console app without any jar loadings) we don't get any errors. So technically it's a violation of Java spec for protected classes but since we use an inner class it works.
So we have different behavior for two cases of "different packages".
Could someone give a clear explanation of how inner class gets access to parent's fields and why it works differently for two cases?
Upvotes: 16
Views: 1002
Reputation: 386
Parent Class
package p1;
public class Parent {
protected String p = "Value from Parent";
public void test() {
System.out.println(p);
}
}
Outer Class
package p1;
public class Outer extends Parent {
class Inner {
public void test() {
Outer.this.p = "Value set from Inner";
System.out.println(Outer.this.p);
}
}
public void test() {
new Inner().test();
}
}
Main Class
package p1;
public class Main {
public static void main(String[] args) {
Parent p = new Parent();
p.test();
p = new Outer();
p.test();
}
}
Output
Value from Parent
Value set from Inner
Upvotes: 1
Reputation: 1435
Declared in different packages, loaded by single class loader - OK
'protected' access is considerate about parent-child relation among classes and allows child classes to access 'protected' members of parent even if they are in different packages. So, I think this is as expected.
Declared in single package, loaded by different class loaders - NOT OK
This has to do with runtime packages. Check this. Now we know that Parent is in different runtime package than Outer and Inner due to being loaded via two different class loaders. At the same time, we also have to remember that Outer is 'child' of Parent but Inner is not. Inner doesn't have an 'Is-a' relation with Parent.
Putting it all together : Since Parent is in a different runtime package, Inner is not able to access Parent's 'protected' members as Inner is not a child of Parent.
Upvotes: 0