Why can outer Java classes access inner class private members?

JavaClassPrivateInner ClassesPrivate Members

Java Problem Overview


I observed that Outer classes can access inner classes private instance variables. How is this possible? Here is a sample code demonstrating the same:

class ABC{
    class XYZ{
        private int x=10;
    }
    
    public static void main(String... args){
        ABC.XYZ xx = new ABC().new XYZ();
        System.out.println("Hello :: "+xx.x); ///Why is this allowed??
    }
}

Why is this behavior allowed?

Java Solutions


Solution 1 - Java

The inner class is just a way to cleanly separate some functionality that really belongs to the original outer class. They are intended to be used when you have 2 requirements:

  1. Some piece of functionality in your outer class would be most clear if it was implemented in a separate class.
  2. Even though it's in a separate class, the functionality is very closely tied to way that the outer class works.

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.

Solution 2 - Java

If you like to hide the private members of your inner class, you may define an Interface with the public members and create an anonymous inner class that implements this interface. Example bellow:

class ABC{
    private interface MyInterface{
         void printInt();
    }

    private static MyInterface mMember = new MyInterface(){
        private int x=10;

        public void printInt(){
            System.out.println(String.valueOf(x));
        }
    };

    public static void main(String... args){
        System.out.println("Hello :: "+mMember.x); ///not allowed
        mMember.printInt(); // allowed
    }
}

Solution 3 - Java

The inner class is (for purposes of access control) considered to be part of the containing class. This means full access to all privates.

The way this is implemented is using synthetic package-protected methods: The inner class will be compiled to a separate class in the same package (ABC$XYZ). The JVM does not support this level of isolation directly, so that at the bytecode-level ABC$XYZ will have package-protected methods that the outer class uses to get to the private methods/fields.

Solution 4 - Java

There's a correct answer appearing on another question similar to this: https://stackoverflow.com/questions/19747812/why-can-the-privite-member-of-an-inner-static-class-be-accessed-by-the-methods-o?lq=1

It says there's a definition of private scoping on JLS - Determining Accessibility:

>Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

Solution 5 - Java

Thilo added a good answer for your first question "How is this possible?". I wish to elaborate a bit on the second asked question: Why is this behavior allowed?

For starters, let's just be perfectly clear that this behavior is not limited to inner classes, which by definition are non-static nested types. This behavior is allowed for all nested types, including nested enums and interfaces which must be static and cannot have an enclosing instance. Basically, the model is a simplification down to the following statement: Nested code have full access to enclosing code - and vice versa.

So, why then? I think an example illustrate the point better.

Think of your body and your brain. If you inject heroin into your arm, your brain gets high. If the amygdala region of your brain see what he believe is a threat to your personally safety, say a wasp for example, he'll make your body turn the other way around and run for the hills without You "thinking" twice about it.

So, the brain is an intrinsic part of the body - and strangely enough, the other way around too. Using access control between such closely related entities forfeit their claim of relationship. If you do need access control, then you need to separate the classes more into truly distinct units. Until then, they are the same unit. A driving example for further studies would be to look at how a Java Iterator usually is implemented.

Unlimited access from enclosing code to nested code makes it, for the most part, rather useless to add access modifiers to fields and methods of a nested type. Doing so is adding clutter and might provide a false sense of safety for new comers of the Java programming language.

Solution 6 - Java

An IMHO important use case for inner classes is the factory pattern. The enclosing class may prepare an instance of the inner class w/o access restrictions and pass the instance to the outside world, where private access will be honored.

In contradiction to [abyx][1] declaring the class static doesn't change access restrictions to the enclosing class, as shown below. Also the access restrictions between static classes in the same enclosing class are working. I was surprised ...

class MyPrivates {
    static class Inner1 { private int test1 = 2; }
    static class Inner2 { private int test2 = new Inner1().test1; }
    	
    public static void main(String[] args) {
    	System.out.println("Inner : "+new Inner2().test2);
    }
}

[1]: https://stackoverflow.com/questions/1801718/outer-java-class-is-able-to-access-inner-class-private-members/1801925#1801925 "abyx"

Solution 7 - Java

Access restrictions are done on a per class basis. There is no way for a method declared in a class to not be able to access all of the instance/class members. It this stands to reason that inner classes also have unfettered access to the members of the outer class, and the outer class has unfettered access to the members of the inner class.

By putting a class inside another class you are making it tightly tied to the implementation, and anything that is part of the implementation should have access to the other parts.

Solution 8 - Java

The logic behind inner classes is that if you create an inner class in an outer class, that's because they will need to share a few things, and thus it makes sense for them to be able to have more flexibility than "regular" classes have.

If, in your case, it makes no sense for the classes to be able to see each other's inner workings - which basically means that the inner class could simply have been made a regular class, you can declare the inner class as static class XYZ. Using static will mean they will not share state (and, for example new ABC().new XYZ() won't work, and you will need to use new ABC.XYZ().
But, if that's the case, you should think about whether XYZ should really be an inner class and that maybe it deserves its own file. Sometimes it makes sense to create a static inner class (for example, if you need a small class that implements an interface your outer class is using, and that won't be helpful anywhere else). But at about half of the time it should have been made an outer class.

Solution 9 - Java

Inner class is regarded as an attribute of the Outer class. Therefore, no matter the Inner class instance variable is private or not, Outer class can access without any problem just like accessing its other private attributes(variables).

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

Solution 10 - Java

Because your main() method is in the ABC class, which can access its own inner class.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHarishView Question on Stackoverflow
Solution 1 - JavaKaleb BraseeView Answer on Stackoverflow
Solution 2 - JavaIchView Answer on Stackoverflow
Solution 3 - JavaThiloView Answer on Stackoverflow
Solution 4 - JavaColin SuView Answer on Stackoverflow
Solution 5 - JavaMartin AnderssonView Answer on Stackoverflow
Solution 6 - JavathomasfrView Answer on Stackoverflow
Solution 7 - JavaTofuBeerView Answer on Stackoverflow
Solution 8 - JavaabyxView Answer on Stackoverflow
Solution 9 - JavaMonMoonkeyView Answer on Stackoverflow
Solution 10 - Javaaberrant80View Answer on Stackoverflow