Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I was shocked today to discover that this code compiles cleanly in Java:

public class A {
  public static class B {
     private static void x() {}
  }
  private static class C {
     private /* So, private to what exactly? */ static void x() {}
  }
  public static void main(String[] args) {
    B.x(); C.x();
  }
}

It seems Java's private keyword indicates only top-level-class-privacy; which, given the general convention to name Java source files by class, means that Java effectively provides only file-level private visibility, not true private visibility. (The equivalent code in C++ does not compile with a visibility error.)

Would anyone be able to explain why Java was designed this way? Or is this just Java's way of telling everyone not to use nested classes? (It certainly hacks in an implementation of a two-way C++ friend relationship, but we already have package-level visibility for that; this seems to make the one-way equivalent impossible. Moreover, it necessitates the compiler creating more hidden accessor methods to circumvent the visibility, and under-the-hood downgrading of nested class visibility control to make all this not error out at runtime. Really, why the trouble?)

share|improve this question
2  
Why can outer Java classes access inner class private members from StackOverflow –  MichaelT Jul 4 '13 at 2:24
    
The benefits and costs are various and not easily weighed against each other, but you are right that it is somewhat surprising. For reference, the original author of javac, Martin Odersky, seems to feel the same way: when inventing Scala, he made the effect configurable, so that the programmer can decide whether something is private to its class, to its class and superclass, or to the file, etc. –  Kilian Foth Jul 4 '13 at 6:48
add comment

1 Answer 1

Welcome to Java.

Your code is in the file for class A. The word "private" in this file means private to class A. Class B is just a part of class A. However, the "private" for method x does serve an important purpose; it means that no code outside of class A can call that method on an instance of class B. This means that while an instance of class B could be available all across the program, any problems caused by method x must be caused somewhere in class A. In a large, complex system this encapsulation makes life a lot easier, both for debugging and for modifying code.

The idea here is that an object of class A can communicate with the rest of the system with instances of classes like B and C while keeping a great deal of control over those instances--since method x can only be called from within A. (And if the classes were not static, A would have even more ways to control B and C.)

In Java and C#, nested classes are completely different things with completely different purposes; do not confuse them. In C#, they're just normal classes with slightly limited scope. In Java, nested classes are very much the agents, or extensions, or representives, of their top-level ancestor. The Java approach won't make too much sense until you work with it a while on a complex system, but if you do, it will become very addictive.

share|improve this answer
    
In C#, a class nested within within a generic class definition will actually behave as a family of class definitions (one for each combination combination of type parameters used in the parent class). For example, given public class Foo<T> { public class Bar { public static int moo; }}, the values of Foo<int>.Bar.moo and Foo<String>.Bar.moo will be independent. That's a behavior which is hardly the same as "limited scope". –  supercat Mar 22 at 19:55
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.