Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can a class load another class' private inner class?

Tags:

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"

like image 456
Evgeniy Dorofeev Avatar asked Dec 24 '12 10:12

Evgeniy Dorofeev


People also ask

Why can outer Java classes access inner class private members?

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 Java classes access inner class private members?

Can inner class access members of outer class? Yes, including the ones declared private , just as any instance method can.

Can outer class access inner class private methods?

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.

Can inner class may extend another class?

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.


2 Answers

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.

like image 69
Hendrik Brummermann Avatar answered Sep 20 '22 04:09

Hendrik Brummermann


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).

like image 38
assylias Avatar answered Sep 21 '22 04:09

assylias