I have
class A { private static class B { B() { } } }
though B is private I load A$B.class from another class without a problem. Why is that allowed?
class C { public static void main(String[] args) throws Exception { System.out.println(Class.forName("A$B").newInstance()); } }
output
A$B@affc70
UPDATE
I understand that the restriction for loading any classes is raised intentionally, but there must be a reasonable explanation why.
Note that package private B{} constructor there is on purpose. If I remove it I will get
java.lang.IllegalAccessException: Class B can not access a member of class A$B with modifiers "private"
Given these requirements, inner classes have full access to their outer class. Since they're basically a member of the outer class, it makes sense that they have access to methods and attributes of the outer class -- including privates.
Can inner class access members of outer class? Yes, including the ones declared private , just as any instance method can.
It can access any private instance variable of the outer class. Like any other instance variable, we can have access modifier private, protected, public, and default modifier. Like class, an interface can also be nested and can have access specifiers.
Inner class can extend it's outer class. But, it does not serve any meaning. Because, even the private members of outer class are available inside the inner class. Even though, When an inner class extends its outer class, only fields and methods are inherited but not inner class itself.
The class loader may load any class, but the access rules are enforced on instantiation.
So why is your code able to instantiate the class?
Inner classes are a big hack at the byte code level because they were implemented to be byte-code compatible with Java 1.0.
So this private inner class at the source code level is in fact package-protected at byte code level. You can verify that by moving class C into another package and making the constructor of B public:
Exception in thread "main" java.lang.IllegalAccessException: Class something.C can not access a member of class A$B with modifiers "public"
Reflection does allow to override access rules by using setAccessible(), but this is not the case here.
This behaviour is compliant with the javadoc:
Note that this method does not check whether the requested class is accessible to its caller.
In other words, forName
can access non accessible classes and won't throw an IllegalAccessExcessException
. And because the constructor is package private, i.e. (I assume) accessible from your calling location, newInstance
does not throw any exceptions either.
If the constructor were not accessible (either because you move it to another package or you make it private), newInstance
would throw an exception.
Regarding your update, if you remove the constructor, you will be calling the default constructor which will have the same access as the class, in this case private (cf JLS 8.8.3: if the class is declared private, then the default constructor is implicitly given the access modifier private).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With