Why can outer Java classes access inner class private members?

102,556

Solution 1

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

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

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

There's a correct answer appearing on another question similar to this: Why can the private member of an nested class be accessed by the methods of the enclosing class?

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

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.

Share:
102,556

Related videos on Youtube

Harish
Author by

Harish

Updated on December 04, 2020

Comments

  • Harish
    Harish over 3 years

    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?

    • Wang Sheng
      Wang Sheng almost 9 years
      This question confused me for quite a while until I see the comment...that explains why I cannot access xx.x on my machine..
    • leon
      leon over 8 years
      The comments confused me, I run the above code in Java 8, it does compile and run. xx.x can be accessed.
    • temporary_user_name
      temporary_user_name over 4 years
      Harish, can you please un-accept the accepted answer (which does not answer the question you asked) and instead accept Martin Andersson's answer down below, which very thoroughly answers it?
    • Josh M.
      Josh M. over 4 years
      FWIW this syntax is absolutely horrendous: new ABC().new XYZ()
    • Moritz Wolff
      Moritz Wolff about 3 years
      Please change the accepted answer - it doesn't give an answer to the question being asked here.
  • Andrew
    Andrew over 12 years
    This answer explains why nested classes have access to private members of their outer class. But the question is why does the outer class have access to private members of nested classes.
  • kevinarpe
    kevinarpe about 11 years
    This is a brilliant snippet of code. Just what I needed. Thanks!
  • anthropomo
    anthropomo almost 11 years
    Just add "and vice versa" to Given these requirements, inner classes have full access to their outer class and now it answers the question.
  • ceving
    ceving over 10 years
    Nice comment but no answer.
  • Colin Su
    Colin Su about 10 years
    This one is not the correct answer to this problem, here does: stackoverflow.com/questions/19747812/…
  • androidyue
    androidyue over 9 years
    Please provider the code that could be able to run. What's more please the reason why the private variable could not be allowed to access.
  • O. R. Mapper
    O. R. Mapper over 9 years
    @anthropomo: No, it does not. Both requirements are perfectly feasible without the outer class having any access to private members of the inner classes.
  • O. R. Mapper
    O. R. Mapper over 9 years
    But then ... the inner class is anonymous. You cannot create several instances of that inner class, or use that inner class for any variable declarations etc.
  • O. R. Mapper
    O. R. Mapper over 9 years
    The outer class can access the private members of static inner classes just as well, so this has nothing to do with static. You say "it makes no sense for the classes to be able to see each other's inner workings", but that's not necessarily the case - what if it makes sense just for the inner class to see the outer class's inner workings, but not vice-versa?
  • O. R. Mapper
    O. R. Mapper over 9 years
    The question is not whether members of the ABC class can access classes nested in the ABC class, but why they can access private members of classes nested in the ABC class in Java.
  • vikky.rk
    vikky.rk about 9 years
    One good example where this is particularly useful is the Builder Pattern, stackoverflow.com/a/1953567/1262000. Parent class just needs a constructor that takes a Builder and access all its member variables. Otherwise you would need to have a private constructor in the parent class with all the private member variables.
  • aberrant80
    aberrant80 almost 9 years
    I answered the question the same day it was asked. Someone edited the question 2 years later, and the downvote came 3 years later. I'm pretty sure whoever edited the question changed the wording of the question entirely too much.
  • Kevin
    Kevin over 8 years
    It may be feasible without giving the outer class access, but giving the outer class is a reasonable solution.
  • et_l
    et_l over 7 years
    @cerving This is actually the only answer that allowed me to see a practical real usage of this otherwise bizarre design decision. The question was why it was decided this way, and this is a great reasoning - a demonstration of the difference between what you might want the outer class to access in the inner class and what you want other unrelated classes to access.
  • shen
    shen about 7 years
    I think this snippet can nicely answer my question.
  • Vishrant
    Vishrant about 6 years
    From current post check this answer stackoverflow.com/questions/1801718/… @Harish I believe this answer does not answer your question
  • Josh M.
    Josh M. almost 6 years
    You can explain anything with words, however, this implementation is "wrong" IMO. If I declare a nested class with private members, they should only be accessible within that nested class (not in the parent). The way it is now, we can't create immutable nested classes. (Please correct me if I'm wrong.)
  • Ram
    Ram almost 6 years
    @O.R. Mapper that's why even if x is public here, it's not allowed like mMember.x.
  • temporary_user_name
    temporary_user_name over 4 years
    This should realllllly be the accepted answer. So clear and thorough. Instead the accepted answer doesn't even address the question.
  • vkelman
    vkelman over 4 years
    Interestingly, creators of Kotlin decided that outer class should not see private members of its inner class. kotlinlang.org/docs/reference/… The same is true in C# stackoverflow.com/questions/2816961/…
  • Josh M.
    Josh M. over 4 years
    IMO this still doesn't answer the question as to why we cannot easily add private fields to an inner class, which the outer class cannot access directly. Unless I'm wrong, this ruins one of the primary cases for inner classes -- creating short-lived "struct-like", immutable types. FWIW C# happily supports this: repl.it/repls/VengefulCheeryInverse
  • nog642
    nog642 over 3 years
    @aberrant80 The revision history is public, and even the original question is pretty clearly asking why.