Re: Need a new access modifier?
John W. Kennedy wrote:
John Ersatznom wrote:
I've read somewhere that inner class access to a "private" member of a
nesting class causes it to be silently treated as "package-private" by
the compiler, with security implications.
A quick test seems to contradict this. "private" appears to be "private".
Which javac and jvm? Or was it statically compiled code with gcj? I
expect the latter especially might differ in implementation.
What test case did you use? I'd suggest
package test;
public class AccessTester1 {
private int foo;
public AccessTester1 (int x) { foo = x; }
public class FooRetriever {
public int getOuterFoo() { return foo; }
}
public FooRetriever getFooRetriever () { return new FooRetriever(); }
}
package test;
public class AccessTester2 {
public static void main (String[] args) {
AccessTester1 a = new AccessTester1(3);
AccessTester1.FooRetriever fr = a.getFooRetriever();
System.out.println(""+fr.getOuterFoo()); // 3
System.out.println(""+a.foo); // Compile error
}
}
This pair should have AccessTester2 fail to compile. Change "private int
foo;" to "int foo;" in AccessTester1 and compile both to get a working
class pair. Change back to "private int foo;" in AccessTester1 and
recompile it only (obviously don't use Eclipse or anything else that
updates everything else automatically!) and run it. It should work.
Remove FooRetriever and change getFooRetriever to int getFoo() (and
change AccessTester2 to replace the 2nd and 3rd lines of main with
"System.out.println(""+a.getFoo());") and it won't compile. Change foo's
declaration to just "int foo;" and it will, and everything works. Now
change it back without recompiling AccessTester2 and AccessTester1
should compile, but AccessTester2 should print "3" and then bomb at
runtime with an access exception of some sort because foo is private.
The *compiler* seems to treat "private" as "private", but the *runtime*
seems to treat it as "package private" when there's an inner class that
accesses the member.
Try also changing FooRetriever to return zero rather than access foo
rather than remove it entirely.
Some of this behavior is probably quite implementation-dependent, but
the failure to throw exceptions at run-time when the private member is
accessed is troubling. Besides security implications, the example above
demonstrates changing semantics for one class when the private
implementation of another is fiddled with, instead of attempted access
to said private implementation always failing in a consistent way. When
code from different sources (e.g. application code and library code, or
code in collaborative efforts) get combined queer dependencies can
result, especially if one of the coders doesn't have access to the
source for some of the other code (e.g. application coder using a
closed-source library).
I guess you can also read the above as yet another argument for open source.