Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136062

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

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

Answers (5)

Hendrik Brummermann
Hendrik Brummermann

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

assylias
assylias

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

Vahid Haratian
Vahid Haratian

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

Peter Lawrey
Peter Lawrey

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

  • trigger the creation of enum instances.
  • give you a reference to a class before it has been initialised.
  • "override" a class in a parent class loader.
  • trigger classes to unload when it is unloaded.
  • give you the byte code for a classes, giving you the raw implementation details.
  • give you a stream for non-class resources in the class path.

Like reflections, it can load a class with private members and it would be rather pointless if it couldn't.

Upvotes: 3

Rahul
Rahul

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

Related Questions