简体   繁体   中英

Multiple .class files generated for a class?

Out of curiosity, why are sometimes multiple Java.class files generated for a class after compilation? For example, my application has six classes. For one class, a total of 10.class files has been generated, starting from MyClass#1 up to MyClass#10.

These are for inner classes and static nested classes . The ones with numbers are anonymous inner classes.

For example:


class Foo {
   class Bar { }
   static class Baz { }
   void run() {
      Helper t = new Helper() {
         int helpMethod() {
            return 2;
         }
      };
    }
}

This will produce class files Foo.class , Foo$Bar.class , Foo$Baz.class and Foo$1.class (for the implementation of the Helper interface)

You get more .class fils from a single source file if

  • the class contains inner classes or static inner classes. Inner classes can nest. Their names are <outer class name>$<inner class name> .

  • inner interfaces which are always static.

  • anonymous inner classes (which in fact are plain inner classes without a name)

  • package access interfaces and classes before and after your main class. You can have an arbitrary number of package access classes and interfaces in a single Java source file. Usually small helper objects that are only used by the class are just put into the same file.

One java source file can generate multiple class files, if your class contains inner classes. Anonymous inner classes are represented by your numbered class files.

Every class in java belongs to a .java-file, but a .java-file can contain multiple classes. That includes inner and anonymous classes. The .class-files generated for inner classes contain a '$' in their name. Anonymous inner classes get numbers.

To add to the answers above, this is another good example of generated inner classes based on Comparators (each Comparator is compiled in a different MyClass$X.class ):

public class MyClass {
    ...

    public void doSomething() {
        ...
        Collections.sort(list, new Comparator<MyObj>() {
            public int compare(MyObj o1, MyObj o2) {
                ...
            }
        });
        ...
    }

    ...
}

If there is one X.java file and if it contains 4 collections.sort() {} then after compilation X.class,X$1.class,X$2.class,X$3.class,X$4.class will get generated.

In case of inner class and static inner class more .class files get generated.

Starting point

Why are sometimes multiple Java.class files generated for a class after compilation? For one class, a total of 10 .class files has been generated, starting from MyClass#1 up to MyClass#10 .

Though this particular question has been around for a while, it's still relevant, and there are a number of useful details available which are not currently reflected in the existing answers.

General behavior

There are a number of ways to create multiple .class files from a single .java file.

Here's an example.

  • Starting with this code in a single file Example.java :
     public class Example { } class Second { }
  • the compiler would produce two class files:
     Example.class Second.class

Anonymous classes

In JLS 15.9 Class Instance Creation Expressions , we can see that there are many ways to create classes. One way is by creating "anonymous" classes, where "anonymous" means the class wasn't given a concrete name in code. From JLS 15.9.5 Anonymous Class Declarations (with added emphasis):

An anonymous class is implicitly declared by a class instance creation expression or by an enum constant that ends with a class body ( §8.9.1 ).

So we have a number of ways to create classes, including anonymously. Anonymous classes – despite not having names – must still be assigned names at compilation time. There are rules about how all classes are named, including anonymous classes, and it is one of these rules which details how a class can end up with something like $1 in the name.

In JLS 13.1 The Form of a Binary , we can see a relevant naming pattern (one of many other patterns):

The binary name of a local class (§14.3) consists of the binary name of its immediately enclosing type, followed by $, followed by a non-empty sequence of digits, followed by the simple name of the local class.

These anonymous classes are what is referenced in the original post ("MyClass#1" and "MyClass#10").

Example: anonymous class

Here's an example that creates an anonymous inner class (" $1 " in the name) by calling new Thread() { } :

public class Example {
    public static void main(String[] args) {
        new Thread() { };
    }
}

This results in two classes:

Example.class
Example$1.class

Additional naming patterns

Anonymous classes are not the only naming patterns which include $ in the name, there are several others. The original question appears to be asking primarily about classes with numbers in the name (like $1 ), but these also exist. In JLS 13.1 The Form of a Binary , there's a decent amount of additional detail. Here's an excerpt showing some of the other naming rules about how to construct a name for a class or interface:

The class or interface must be named by its binary name, which must meet the following constraints:

  • The binary name of a member type (§8.5, §9.5) consists of the binary name of its immediately enclosing type, followed by $, followed by the simple name of the member.

  • The binary name of an anonymous class (§15.9.5) consists of the binary name of its immediately enclosing type, followed by $, followed by a non-empty sequence of digits.

  • The binary name of a type variable declared by a generic class or interface (§8.1.2, §9.1.2) is the binary name of its immediately enclosing type, followed by $, followed by the simple name of the type variable.

  • The binary name of a type variable declared by a generic method (§8.4.4) is the binary name of the type declaring the method, followed by $, followed by the descriptor of the method (JVMS §4.3.3), followed by $, followed by the simple name of the type variable.

  • The binary name of a type variable declared by a generic constructor (§8.8.4) is the binary name of the type declaring the constructor, followed by $, followed by the descriptor of the constructor (JVMS §4.3.3), followed by $, followed by the simple name of the type variable.

As Peter Kofler mentioned, <outer class name>$<inner class name> is the format used--since there may be inner classes contained within a class. This is important for the compilation process during which the symbol table is generated. The symbol table contains information about classes, objects, variables, scope, etc. When I wrote an undergraduate compiler, I did something similar for my symbol table as I would do something like <class name>.<method> , or <class name>.<method>.<variable> . It's a clean way to represent a piece of data in the symbol table, and is why you are seeing those being generated.

More than one class will be generated on compilation, Only if your class is having inner class.

refer: Why does Java code with an inner class generates a third SomeClass$1.class file?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM