Reputation: 136062
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"
Upvotes: 21
Views: 1515
Reputation: 8312
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.
Upvotes: 12
Reputation: 328735
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).
Upvotes: 8
Reputation: 736
Using reflection Even you can change the modifiers
class MyClass{
private int value;
}
Field value = MyClass.class.getDeclaredField("value");
value.setAccessible(true);
Upvotes: 0
Reputation: 533680
While reflections is a good comparison, the class loader goes beyond what the reflection library can do. For example, a class loader can create classes, which you can't do with reflections. It can also
Like reflections, it can load a class with private members and it would be rather pointless if it couldn't.
Upvotes: 3
Reputation: 16355
Reflection is commonly used by programs which require the ability to examine or modify the runtime behaviour of applications running in the Java virtual machine.
It's a tool that lets one break some rules, one can throw it over his foot or use it properly.
Reflection provides a mechanism for accessing information about classes through means which are usually not available by regular interaction between classes and objects.
One of such is allowing access to private fields from outside classes and objects.
However, both getDeclaredField()
and setAccessible()
are actually checked by the security manager and will throw an exception when your code is not allowed to do this. Many reflection tricks may not work with an active security manager.
Upvotes: 3