2

I was surprised to see that a private constructor of a nested class is still callable from the nesting class. For example:

 public class A{
      public void foo(){
           //private constructor of B
           //can be called from A
           B b = new B();
      }

      //nested class
      public static class B{
          private B(){
          }
      }
 }

Does this mean that there is no way to enforce the singleton pattern on a nested class? Or am I missing something fundamental here?

fo_x86
  • 2,583
  • 1
  • 30
  • 41

3 Answers3

3

It's not just the constructor, any private field or method is accessible:

public class Main {

    public static void main(final String[] args) {
        final B b = new B();
        b.whut();
    }

    public static class B {
        private B() {
            System.out.println("hey");
        }

        private void whut() {
            System.out.println("wut?");
        }
    }

}

Outer classes have access to private fields of their nested classes:

http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

falsarella
  • 12,217
  • 9
  • 69
  • 115
Majid Laissi
  • 19,188
  • 19
  • 68
  • 105
1

Does this mean that there is no way to enforce the singleton pattern on a nested class?

It is anyway difficult to implement the singleton (anti) pattern in Java. enums offer a good way, and they work with nesting too:

Does this mean that there is no way to enforce the singleton pattern on a nested class?

enum Outer {
    O;
    enum Inner { I }
}
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
1

Does this mean that there is no way to enforce the singleton pattern on a nested class?

It depends what you mean by "enforce".

If you mean, can you get the compiler to prevent foo from breaking your 'singleton' invariant - then "No". (Or at least, not unless you make 'B' a non-nested class first ...)

However, the outer class and the nested classes are all defined in the same source file, and should be considered as part of the same unit of abstraction. (And in fact, the fact that A.foo() can call A.B.B means the latter is true in a very real sense.) Therefore, it is the responsibility off A and everything within it to maintain the entire abstraction's invariants ... including singleton-ness of B.

From that perspective, a foo method that breaks the invariant is no different to a hypothetical method on a non-nested "singleton" class that breaks the invariant; e.g.

public Single {
    private static Single s = new Single();
    public static Single getInstance() { return s; }
    private Single() { ... }

    public void foo() {
        Single ss = new Single();  // breaks the invariant!!
        ...
    }
}

Note the problem ... in both cases ... is that the abstraction is breaking its own invariants.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216