Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java inner class visibility puzzle

Consider the following case:

public class A {
  public A() { b = new B(); }
  B b;
  private class B { }
}

From a warning in Eclipse I quote that: the java complier emulates the constructor A.B() by a synthetic accessor method. I suppose the compiler now goes ahead and creates an extra "under water" constructor for B.

I feel this is rather strange: why would class B not be visible as a.k.o. field in A? And: does it mean that class B is no longer private at run time? And: why behaves the protected keyword for class B different?

public class A {
  public A() { b = new B(); }
  B b;
  protected class B { }
}
like image 230
Gerard Avatar asked Jul 06 '09 09:07

Gerard


2 Answers

I know this question is now almost three years old, but I find that a part of the question is still not answered:

And: does it mean that class B is no longer private at run time?

Carlos Heubergers comment on skaffmans answer suggests, class B is still private for other classes in the package.

He is probably right for the Java programming language, i.e. it is not possible to refer to class B from an other class. At least not without using reflection (with which also private class members may be accessed from the outside), but this is another issue.

But as the JVM does not have any concept of an inner class (as skaffman states), I asked myself how an "accessible by only one class" visibility is realized at the bytecode level. The answer: It isn't realized at all, for the JVM the inner class looks like a normal package private class. This is, if you write bytecode for yourself (or modify one generated by the compiler) you can access class B without problems.

You can access all synthetic accessor methods from all classes in the same package, too. So if you assign a value to a private field of class A in a method of class B, a synthetic accessor method with default (i.e. package private) visibility is generated in class A (named something like access$000) that sets the value for you. This method is supposed to only be called from class B (and indeed it can only be called from there using the Java language). But from the JVMs point of view, this is just a method as any other and can be called by any class.

So, to answer the question:

  • From the Java languages point of view, class B is and stays private.
  • From the JVMs point of view, class B (or better: class A$B) is not private.
like image 190
siegi Avatar answered Oct 10 '22 10:10

siegi


Inner classes are essentially a hack introduced in Java 1.1. The JVM doesn't actually have any concept of an inner class, and so the compiler has to bodge it. The compiler generates class B "outside" of class A, but in the same package, and then adds synthetic accessors/constructors to it to allow A to get access to it.

When you give B a protected constructor, A can access that constructor since it's in the same package, without needing a synthetic constructor to be added.

like image 42
skaffman Avatar answered Oct 10 '22 09:10

skaffman