28

I wrote the following code to implement the Singleton pattern:

public final class Test {
     static final class TestHolder {
         private static final Test INSTANCE = new Test();
     }     

     private Test() {}

     public static Test getInstance() {
         return TestHolder.INSTANCE;
     }
}

When I compile this file, it should generate Test.class and Test$TestHolder.class, but it also generates Test$1.class. This doesn't make sense. So why and how would this be?

J. Rahmati
  • 735
  • 10
  • 37
handrenliang
  • 1,047
  • 1
  • 10
  • 21
  • http://c2.com/cgi/wiki?AnonymousInnerClass – ddavison Jun 09 '13 at 05:01
  • 3
    @sircapsalot the question is *where is the anonymous class*. – Luiggi Mendoza Jun 09 '13 at 05:01
  • 3
    This is the type of questions worth to upvote. – Luiggi Mendoza Jun 09 '13 at 05:07
  • I don't get that `Test$1.class` file here (JDK 7 or 6). Does anyone else? – acdcjunior Jun 09 '13 at 05:08
  • Yes, `javac 1.6.0_45` on my Mac creates it, and I've explained its purpose below. – Ernest Friedman-Hill Jun 09 '13 at 05:10
  • Anyway, as weird as it gets, my compiler (Eclipse's JDT) does not generate it at all, no matter what compliance level is set (with `javap` I can clearly see the `Test` class being passed to the constructor). – acdcjunior Jun 09 '13 at 05:29
  • Eclipse has its own compiler, and is free to implement this another way. – Ernest Friedman-Hill Jun 09 '13 at 05:31
  • Yeah, Eclipse has Eclipse JDT as compiler. I wouldnt say it is free, as the JVM that will run its bytecode is the same that will run `javac`'s. This leads us to believe that the creation of `Test$1.class` is a design choice, not a workaround to a JVM limitation. – acdcjunior Jun 09 '13 at 05:42
  • There are a couple of other obvious implementations: the compiler could add a factory method to `Test`, or it could make the private constructor package-protected instead. I think all of these implementations *do* have to work around the fundamental issue that a class can't access another class's private bits, and the JVM enforces that at runtime. – Ernest Friedman-Hill Jun 09 '13 at 05:44
  • @ErnestFriedman-Hill what can I do to prevent compiler generating such class file? I make the Test constructor package scope, it doesn't work. – handrenliang Jun 09 '13 at 05:59
  • @ErnestFriedman-Hill Both compilers generate a synthetic constructor with package-level visibility. The difference is that `javac`'s uses `Test$1` as parameter and JDT uses `Test` as parameter. It is clear what it does with `Test$1` and when it creates it, but not *really* why. Btw, `TestHolder` never calls `Test$1`'s constructor as your answer says. – acdcjunior Jun 09 '13 at 06:27
  • @handrenliang Making `Test`'s constructor have package-level visibility will do the trick. You might need to clean your project to see `Test$1.class` gone. – acdcjunior Jun 09 '13 at 06:37
  • @acdcjunior I have cleaned it before compiling. My compiler is 1.6.0_38 – handrenliang Jun 09 '13 at 06:41
  • @acdcjunior sorry for my mistake. Package-level visibility works. I have another anomymous inner class. – handrenliang Jun 09 '13 at 06:47
  • @handrenliang I have 1.6.0_39 and this code does not generate a `Test$1.class`: `public final class Test { static final class TestHolder { private static final Test INSTANCE = new Test(); } Test() {} public static Test getInstance() { return TestHolder.INSTANCE; } }` – acdcjunior Jun 09 '13 at 06:48
  • @handrenliang Aw, ok :) – acdcjunior Jun 09 '13 at 06:49

1 Answers1

31

Class TestHolder needs to call the private constructor in Test. But it's private, and can't actually be called from another class. So the compiler plays a trick. It adds a new non-private constructor to Test which only it knows about! That constructor takes an (unused) instance of this anonymous class Test$1 -- which nobody knows exists. Then TestHolder creates an instance of Test$1 and calls that constructor, which is accessible (it's default-protected.)

You can use javap -c Test (and javap -c Test\$1, and javap -c Test\$TestHolder) to see the code. It's quite clever, actually!

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186