SoFunction
Updated on 2025-04-14

The principle and function of Java compilation to generate multiple .class files

Below, as an experienced developer, after performing compilation in a Java project, you may find that a .java source file sometimes produces multiple .class files. This phenomenon is analyzed in detail from the technical implementation level.

1. Internal class mechanism and .class file generation

Member inner class (regular inner class)

// 
public class Outer {
    public class Inner {
        void display() {
            ("Inner class");
        }
    }
}

After compilation, it will generate:

  • Outer$

Implementation principle

  • The compiler generates a separate .class file for the internal class
  • The inner class implicitly holds references to the outer class (by synthesizing constructor parameters)
  • Accessing private members of external classes is a synthetic accessor method generated by the compiler.

Local inner class (method inner class)

public class Outer {
    void method() {
        class LocalInner {
            void show() {
                ("Local inner");
            }
        }
        new LocalInner().show();
    }
}

Generate file:

  • Outer$(Number prefix indicates the order of definition)

Features

  • The class name contains the method information that defines it
  • Unable to access from outside the method
  • Can capture final local variables of the method

Anonymous internal class

public class Outer {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            ("Anonymous");
        }
    };
}

Generate file:

  • Outer$

Implementation details

  • Class names use numeric numbers instead of specific names
  • Each anonymous class generates a separate .class file
  • Implicitly implement a specified interface or inherit a specified class

2. Special treatment of Lambda expressions

public class LambdaExample {
    public static void main(String[] args) {
        Runnable r = () -> ("Lambda");
        ();
    }
}

Generating files may include:

  • LambdaExample$$Lambda$(The specific name depends on the JVM implementation)

The underlying mechanism

  1. Java 7 introducedinvokedynamicinstruction
  2. useLambdaMetafactoryDynamically generated implementation classes
  3. Modern JVMs usually don't generate physical .class files, but dynamically generate bytecode at runtime

3. Compilation and processing of enum types

public enum Color {
    RED, GREEN, BLUE;
}

Generate file:

  • Color$(May contain enumeration-related auxiliary information)

Enumeration Compilation Features

  • Each enum constant is an instance of the enum class
  • Compiler generationvalues()andvalueOf()method
  • It may generate additional auxiliary classes to handle enumeration serialization and other features

4. Compiler-generated synthetic class

Bridge Methods

class Parent<T> {
    void set(T t) { /*...*/ }
}

class Child extends Parent<String> {
    @Override
    void set(String s) { /*...*/ }
}

generate:

  • May contain synthesis classes related to bridging methods

Type erase auxiliary class

After generic type erasing, the compiler may generate auxiliary classes to ensure type safety.

5. Technical verification methods

Decompilation using javap

javap -v Outer$

View the synthetic members

javap -p  | grep synthetic

Analyze bytecode

javac -g:none -XD-printflat -XD-printsource 

6. Precautions for actual development

Class loading impact:

The inner class will not be automatically loaded with the outer class

Special attention should be paid to reflection$Symbol processing

Serialization considerations:

Anonymous and local classes cannot be serialized

Internal class serialization will serialize external class instances together

Build tool processing:

&lt;!-- MavenConfiguration example --&gt;
&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;&lt;/groupId&gt;
            &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
            &lt;version&gt;3.8.1&lt;/version&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;

Debugging support:

The debugging information will include internal class source location maps

The stack trace of anonymous class shows the number number

7. Performance and design considerations

Class loading overhead:

Each .class file needs to be loaded separately

A large number of anonymous classes may increase PermGen/Metaspace pressure

Design alternatives:

// Lambdas that replace anonymous classesRunnable r = () -&gt; ("Better");

// Static nested classes that replace inner classespublic static class StaticNested { ... }

Modular impact:

Nested classes need to be explicitly exported in JPMS module system

Reflection access to internal classes requires--add-opensparameter

Summarize

This is the article about the principles and functions of Java compilation and generating multiple .class files. For more related Java compilation and generating multiple .class files, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!