201

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?

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
Harish
  • 7,589
  • 10
  • 36
  • 47
  • This question confused me for quite a while until I see the comment...that explains why I cannot access xx.x on my machine.. – Wang Sheng Jul 07 '15 at 10:22
  • 4
    The comments confused me, I run the above code in Java 8, it does compile and run. xx.x can be accessed. – leon Feb 26 '16 at 18:38
  • 1
    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? – temporary_user_name Dec 03 '19 at 18:43
  • 1
    FWIW this syntax is absolutely horrendous: `new ABC().new XYZ()` – Josh M. Mar 02 '20 at 20:22
  • Please change the accepted answer - it doesn't give an answer to the question being asked here. – Moritz Wolff Mar 13 '21 at 23:41

10 Answers10

82

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.

Kaleb Brasee
  • 51,193
  • 8
  • 108
  • 113
  • 240
    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. – Andrew Feb 29 '12 at 18:04
  • 17
    Just add "and vice versa" to _Given these requirements, inner classes have full access to their outer class_ and now it answers the question. – anthropomo Jun 14 '13 at 15:10
  • 14
    This one is not the correct answer to this problem, here does: http://stackoverflow.com/questions/19747812/why-can-the-privite-member-of-an-inner-static-class-be-accessed-by-the-methods-o?lq=1 – Colin Su Mar 28 '14 at 03:08
  • 4
    @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 Dec 16 '14 at 12:00
  • One good example where this is particularly useful is the Builder Pattern, http://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. – vikky.rk May 07 '15 at 23:57
  • It may be feasible without giving the outer class access, but giving the outer class is a reasonable solution. – Kevin Feb 13 '16 at 02:44
  • From current post check this answer https://stackoverflow.com/questions/1801718/why-can-outer-java-classes-access-inner-class-private-members#answer-1801801 @Harish I believe this answer does not answer your question – Vishrant Apr 29 '18 at 00:11
  • Interestingly, creators of Kotlin decided that outer class should not see private members of its inner class. https://kotlinlang.org/docs/reference/visibility-modifiers.html#classes-and-interfaces The same is true in C# https://stackoverflow.com/questions/2816961/how-to-get-access-to-private-members-of-nested-class – vkelman Dec 03 '19 at 22:37
68

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
    }
}
Ram
  • 3,887
  • 4
  • 27
  • 49
Ich
  • 689
  • 5
  • 2
  • This is a brilliant snippet of code. Just what I needed. Thanks! – kevinarpe Mar 08 '13 at 11:23
  • 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. – androidyue Oct 02 '14 at 03:49
  • 8
    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 Dec 16 '14 at 12:02
  • @O.R. Mapper that's why even if `x` is public here, it's not allowed like `mMember.x`. – Ram Aug 22 '18 at 18:48
62

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.

Thilo
  • 257,207
  • 101
  • 511
  • 656
20

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.

Community
  • 1
  • 1
Colin Su
  • 4,613
  • 2
  • 19
  • 19
10

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 be 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. In other words: 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 rather useless to add access modifiers to fields and methods of a nested private type. Doing so is adding clutter and might provide a false sense of safety for new comers of the Java programming language.

Martin Andersson
  • 18,072
  • 9
  • 87
  • 115
  • 1
    This should realllllly be the accepted answer. So clear and thorough. Instead the accepted answer doesn't even address the question. – temporary_user_name Dec 03 '19 at 18:43
  • 1
    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: https://repl.it/repls/VengefulCheeryInverse – Josh M. Mar 02 '20 at 20:34
  • 1
    _"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."_ only if you don't return or expose those nested classes to the outside world, which is a common thing to do. Also, if you use default access for fields and methods of a nested class, it is accessible to the rest of your package, which is probably not what you want. – Mark Rotteveel Feb 08 '23 at 11:27
  • Thank you Mark. I removed "for the most part" and added "private". Let me know if you have an idea on how to make the answer better ❤️ – Martin Andersson Jun 12 '23 at 13:28
5

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 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);
    }
}
Community
  • 1
  • 1
thomasfr
  • 51
  • 1
  • 2
  • 1
    Nice comment but no answer. – ceving Sep 04 '13 at 08:42
  • @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. – et_l Sep 29 '16 at 09:25
3

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

Pang
  • 9,564
  • 146
  • 81
  • 122
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
3

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.

abyx
  • 69,862
  • 18
  • 95
  • 117
  • 2
    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 Dec 16 '14 at 12:04
-1

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;
}
}
-2

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

aberrant80
  • 12,815
  • 8
  • 45
  • 68
  • 2
    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. – O. R. Mapper Dec 16 '14 at 12:07
  • 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. – aberrant80 Aug 12 '15 at 09:11
  • @aberrant80 The [revision history](https://stackoverflow.com/posts/1801718/revisions) is public, and even the original question is pretty clearly asking _why_. – nog642 Oct 27 '20 at 17:08