Main method

How main is executed

import java.lang.*;
import java.util.*;

class Test {}

The above code will compile successfully. The javac compiler is not responsible for checking whether the class "Test" contains the main() method. The responsibility falls on the JVM (Java Virtual Machine) at runtime, to check whether the class "Test" contains the main() method. If the JVM is unable to find the main method, the we will get a runtime exception java.lang.NoSuchMethodError: main. If however the JVM finds the main method, it will automatically execute it.

Main method prototype

The JVM always looks for the main method prototype: public static void main(String[] args). It is possible to rename the main method and name it to your own custom main method name, maybe rename it to "customMain". Doing this however means you also have to customise the JVM, to search for the new method prototype you have renamed your main method to.

The prototype for main is always public static void main(String[] args) because:

  • public: Because the JVM need to be able to call the main method from anywhere. So it has to be public.
  • static: When the main method is being executed, the class does not have any objects, and JVM has to be able to call the main method without existing objects. So it has to be static.
  • void: Since the JVM calls the main method, it must return void because JVM won't use the return value, and hence does not expect the return value.
  • main: This is the name configured inside the JVM.
  • String[] args: Command line arguments

The main method prototype is strict, any modification to the prototype will cause a "NoSuchMethodError: main" Runtime Exception.

While the prototype is strict there are many different forms the prototype can take:

import java.lang.*;
import java.util.*;

class Test {
    public static void main(String[] args){};
    // public static void main(String[] params){}; // VALID: can have a different valid Java argument identifier
    // static public void main(String[] args){}; // VALID: In Java access modifiers can be in any order
    // public static void main(String... args){}; // VALID: Var-Arg parameter can be used in place of one-dimensional array
    // public static void main(String args[]){}; // VALID: One dimensional array can be declared in any valid way
    // public static void main(String []args){}; // VALID: One dimensional array can be declared in any valid way
}

Main method can also be declared with final, synchronized and strictfp modifiers. These modifiers are also permitted because these are valid non-access modifiers that can be applied to methods.

  • final: Prevents the main method from being overridden in a subclass. Since main is a static method, this ensures it cannot be hidden (a form of method overriding for static methods), maintaining the intended entry point
  • synchronized: Ensures only one thread can execute the main method at a time. While the JVM calls main only once, this can be relevant in multi-threaded environments where other threads might call main indirectly (though not standard practice). It acquires the class-level lock, which can block other static synchronized methods.
  • strictfp: Ensures consistent floating-point arithmetic results across different platforms by restricting floating-point calculations to the IEEE 754 standard. This has no special effect on main itself but applies to all floating-point operations within it.

These modifiers are syntactically valid and do not conflict with the main method's role as the program's entry point. However, using synchronized is generally unnecessary and strictfp is rarely needed in practice.

import java.lang.*;
import java.util.*;

class Test {
    static final synchronized strictfp public void main(String... params){
        System.out.println("Valid main");
    };
}

Main method overloading

Overloading of main method is permitted as the JVM will always call the String[] argument main method. The other overloaded method has to be explicitly called like a normal method call.

import java.lang.*;
import java.util.*;

class Test {
    public static void main(String[] args){
        System.out.println("String[] main");
    };
    public static void main(int[] args){
        System.out.println("int[] main");
    };
}

Parent and Child class main

import java.lang.*;
import java.util.*;

class Parent {
    public static void main(String[] args){
        System.out.println("Parent main");
    };
}
    
class Child extends Parent {
}
javac Parent.java
ls
Child.class Parent.class Parent.java
java Parent
Parent main
java Child    
Parent main

The inheritance concept is applicable to the main method. In the above example, when child does not have a main method, while executing the child class, the parent main method, will be executed.

import java.lang.*;
import java.util.*;

class Parent {
    public static void main(String[] args){
        System.out.println("Parent main");
    };
}
    
class Child extends Parent {
    // Method hiding, not method overloading
    public static void main(String[] args){
        System.out.println("Child main");
    };
}
javac Parent.java
ls
Child.class Parent.class Parent.java
java Parent
Parent main
java Child    
Child main

In the example above, both the Parent and Child class have a main method. This is method hiding in this case, not method overriding. In this case, when the Child class in executed, it executes the main method in the Child class, not the inherited Parent class main method.

For main method, method overloading and inheritance is permitted. Method overriding is not permitted; method hiding is used instead.

Main method enhancements in Java 1.7

import java.lang.*;
import java.util.*;

class Test {
}
Java 1.6
javac Test.java
java Test
Exception in thread "main" java.lang.NoSuchMethodError: main
Java 1.7
javac Test.java
java Test
Error: Main method not found in class Test, please define the main method as:
    public static void main(String[] args)

If class does not have a main method, a runtime exception is thrown, the example above shows the difference between v1.6 and v1.7. The enhancement made in this case was the runtime error message being displayed.

import java.lang.*;
import java.util.*;

class Test {
    static {
        System.out.println("Static Block");
    }
}
Java 1.6
javac Test.java
java Test
Static Block
Exception in thread "main" java.lang.NoSuchMethodError: main
Java 1.7
javac Test.java
java Test
Error: Main method not found in class Test, please define the main method as:
    public static void main(String[] args)

The example above shows another enhancement in v1.7, where main method is mandatory to start any program execution. Even if a class has a static block, a main method is still required. Whereas in Java v1.6, main method was not mandatory to execute a static block, but then when it tries to execute main method, a runtime error is thrown.

import java.lang.*;
import java.util.*;

class Test {
    static {
        System.out.println("Static Block");
        System.exit(0);
    }
}
Java 1.6
javac Test.java
java Test
Static Block
Java 1.7
javac Test.java
java Test
Error: Main method not found in class Test, please define the main method as:
    public static void main(String[] args)

Similarly, the example above shows in v1.7, where main method is mandatory to start any program execution. Even if a class has a static block, a main method is still required. Whereas in Java v1.6, main method was not mandatory to execute a static block, however in this case because of the System.exit(0);. the program shuts down the JVM and does not try to execute the main method, meaning, unlike previously, no runtime error is thrown in this v1.6 example.

import java.lang.*;
import java.util.*;
import java.io.*;

class Test {
    static {
        System.out.println("Static Block");
    }

    public static void main(String... args) {
        System.out.println("main method);
    }
}
Java 1.6
javac Test.java
java Test
Static Block
main method
Java 1.7
javac Test.java
java Test
Static Block
main method

In the example above, in both Java 1.6 and Java 1.7, the program is valid. Even though in Java 1.7, the JVM checks if the main method is present initially before running the program, the order of execution stays the same, so the main method does not get executed first in this case, the static block always get executed before main.

Image illustrating the order of execution in Java version 1.6.
Image illustrating the order of execution in Java version 1.6.
Image illustrating the order of execution in Java version 1.7.
Image illustrating the order of execution in Java version 1.7.