Search code examples
javaruntimeanonymous-class

Are Java anonymous classes created at runtime?


Are anonymous Java classes created at runtime or ahead of time by the compiler?

According to the Java docs, They are like local classes except that they do not have a name, so my guess would be they are created ahead of time. If you can cite your source or know how to test such a thing please let me know!


Solution

  • They're created by the compiler. You can see them by just compiling some code and looking at what you get on disk. You'll end up with things like Foo$1.class where Foo is the class that contains the anonymous method.

    For example:

    public class Test {
        public static void main(String[] args) {
            Runnable runnable = new Runnable() {
                @Override public void run() {
                    System.out.println("Hi");
                }
            };
        }
    }
    
    > javac Test.java
    > dir Test*.class
    Test.class
    Test$1.class
    
    > javap -c Test$1
    
    Compiled from "Test.java"
    final class Test$1 implements java.lang.Runnable {
      Test$1();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public void run();
        Code:
           0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: ldc           #3                  // String Hi
           5: invokevirtual #4                  // Method java/io/PrintStream.println[...]
           8: return
    }
    

    As far as the JVM is concerned, they're just ordinary classes. The various language features added by the compiler, such as the encoding instance where that's relevant, are implemented via extra methods, constructor parameters and fields that are effectively hidden from you by having names that you can't refer to.

    It's not that the generated class doesn't have a name, really - it's just that it's a name which is strongly discouraged for manual code. From JLS 3.8:

    The "Java letters" include uppercase and lowercase ASCII Latin letters A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical reasons, the ASCII underscore (_, or \u005f) and dollar sign ($, or \u0024). The $ sign should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems.

    So in theory you could access Test$1 in source code - but javac appears to prevent you from doing so, in ways I haven't fathomed yet. (I think it uses the metadata in the class file to check that it was compiled from an anonymous inner class.) That makes it "more or less" anonymous from a language perspective.