This is just convention. In fact, even the name main(), and the arguments passed in are purely convention.
When you run java.exe (or javaw.exe on Windows), what is really happening is a couple of Java Native Interface (JNI) calls. These calls load the DLL that is really the JVM (that's right - java.exe is NOT the JVM). JNI is the tool that we use when we have to bridge the virtual machine world, and the world of C, C++, etc... The reverse is also true - it is not possible (at least to my knowledge) to actually get a JVM running without using JNI.
Basically, java.exe is a super simple C application that parses the command line, creates a new String array in the JVM to hold those arguments, parses out the class name that you specified as containing main(), uses JNI calls to find the main() method itself, then invokes the main() method, passing in the newly created string array as a parameter. This is very, very much like what you do when you use reflection from Java - it just uses confusingly named native function calls instead.
It would be perfectly legal for you to write your own version of java.exe (the source is distributed with the JDK) and have it do something entirely different. In fact, that's exactly what we do with all of our Java-based apps.
Each of our Java apps has its own launcher. We primarily do this so we get our own icon and process name, but it has come in handy in other situations where we want to do something besides the regular main() call to get things going (For example, in one case we are doing COM interoperability, and we actually pass a COM handle into main() instead of a string array).
So, long and short: the reason it is static is b/c that's convenient. The reason it's called 'main' is that it had to be something, and main() is what they did in the old days of C (and in those days, the name of the function was important). I suppose that java.exe could have allowed you to just specify a fully qualified main method name, instead of just the class (java com.mycompany.Foo.someSpecialMain) - but that just makes it harder on IDEs to auto-detect the 'launchable' classes in a project.
The method is static because otherwise there would be ambiguity: which constructor should be called? Especially if your class looks like this:
public class JavaClass{
protected JavaClass(int x){}
public void main(String[] args){
}
}
Should the JVM call new JavaClass(int)
? What should it pass for x
?
If not, should the JVM instantiate JavaClass
without running any constructor method? I think it shouldn't, because that will special-case your entire class - sometimes you have an instance that hasn't been initialized, and you have to check for it in every method that could be called.
There are just too many edge cases and ambiguities for it to make sense for the JVM to have to instantiate a class before the entry point is called. That's why main
is static.
I have no idea why main
is always marked public
though.
The main
method in C++, C# and Java are static.
This is because they can then be invoked by the runtime engine without having to instantiate any objects then the code in the body of main
will do the rest.
This is how Java Language is designed and Java Virtual Machine is designed and written.
Check out Chapter 12 Execution - Section 12.1.4 Invoke Test.main:
Finally, after completion of the initialization for class Test (during which other consequential loading, linking, and initializing may have occurred), the method main of Test is invoked.
The method main must be declared public, static, and void. It must accept a single argument that is an array of strings. This method can be declared as either
public static void main(String[] args)
or
public static void main(String... args)
Check out Chapter 2 Java Programming Language Concepts - Section 2.17 Execution:
The Java virtual machine starts execution by invoking the method main of some specified class and passing it a single argument, which is an array of strings. This causes the specified class to be loaded (§2.17.2), linked (§2.17.3) to other types that it uses, and initialized (§2.17.4). The method main must be declared public, static, and void.
Download and extract the source jar and see how JVM is written, check out ../launcher/java.c
, which contains native C code behind command java [-options] class [args...]
:
/*
* Get the application's main class.
* ... ...
*/
if (jarfile != 0) {
mainClassName = GetMainClassName(env, jarfile);
... ...
mainClass = LoadClass(env, classname);
if(mainClass == NULL) { /* exception occured */
... ...
/* Get the application's main method */
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
"([Ljava/lang/String;)V");
... ...
{ /* Make sure the main method is public */
jint mods;
jmethodID mid;
jobject obj = (*env)->ToReflectedMethod(env, mainClass,
mainID, JNI_TRUE);
... ...
/* Build argument array */
mainArgs = NewPlatformStringArray(env, argv, argc);
if (mainArgs == NULL) {
ReportExceptionDescription(env);
goto leave;
}
/* Invoke main method. */
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
... ...
Let's simply pretend, that static
would not be required as the application entry point.
An application class would then look like this:
class MyApplication {
public MyApplication(){
// Some init code here
}
public void main(String[] args){
// real application code here
}
}
The distinction between constructor code and main
method is necessary because in OO speak a constructor shall only make sure, that an instance is initialized properly. After initialization, the instance can be used for the intended "service". Putting the complete application code into the constructor would spoil that.
So this approach would force three different contracts upon the application:
main
method1. Ok, this is not surprising.abstract
. Otherwise, the JVM could not instantiate it.The static
approach on the other hand only requires one contract:
main
method1.Here neither abstract
nor multiple constructors matters.
Since Java was designed to be a simple language for the user it is not surprising that also the application entry point has been designed in a simple way using one contract and not in a complex way using three independent and brittle contracts.
Please note: This argument is not about simplicity inside the JVM or inside the JRE. This argument is about simplicity for the user.
If it wasn't, which constructor should be used if there are more than one?
There is more information on the initialization and execution of Java programs available in the Java Language Specification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With