Java main()方法的方法签名是:
public static void main(String[] args){ ... }
这种方法是否有理由是静态的?
这只是惯例.事实上,甚至名称main()和传入的参数都是纯粹的约定.
当您运行java.exe(或Windows上的javaw.exe)时,真正发生的是几个Java本机接口(JNI)调用.这些调用加载了真正是JVM的DLL(这是正确的 - java.exe不是JVM).当我们必须桥接虚拟机世界,以及C,C++等世界时,JNI是我们使用的工具......反过来也是如此 - 至少据我所知,实际上不可能获得JVM在不使用JNI的情况下运行.
基本上,java.exe是一个超级简单的C应用程序,它解析命令行,在JVM中创建一个新的String数组来保存这些参数,解析出你指定为包含main()的类名,使用JNI调用来查找main()方法本身,然后调用main()方法,将新创建的字符串数组作为参数传入.这非常非常类似于使用Java反射时的操作 - 它只是使用容易混淆命名的本机函数调用.
编写自己的java.exe版本(源代码随JDK一起发布)并让它完全不同,这对你来说是完全合法的.事实上,这正是我们对所有基于Java的应用程序所做的.
我们的每个Java应用程序都有自己的启动器.我们主要这样做,所以我们得到了自己的图标和进程名称,但是在其他我们希望除了常规main()调用之外还要执行某些操作的情况下它已经派上用场了(例如,在一种情况下我们正在做COM互操作性,我们实际上将COM句柄传递给main()而不是字符串数组.
所以,长短:它是静态的原因是b/c方便.它被称为"主要"的原因是它必须是某种东西,而main()就是它们在C的旧时代所做的事情(在那些日子里,函数的名称很重要).我想java.exe可以让你只指定一个完全限定的主方法名,而不只是指定类(java com.mycompany.Foo.someSpecialMain) - 但这只会让IDE更难以自动检测'在项目中启动"课程".
该方法是静态的,否则会有歧义:应该调用哪个构造函数?特别是如果你的班级看起来像这样:
public class JavaClass{ protected JavaClass(int x){} public void main(String[] args){ } }
JVM应该打电话new JavaClass(int)
吗?应该通过x
什么?
如果没有,JVM是否应该在JavaClass
不运行任何构造函数方法的情况下实例化?我认为它不应该,因为这将特殊情况下你的整个类 - 有时你有一个尚未初始化的实例,你必须在每个可以调用的方法中检查它.
有很多边缘情况和含糊之处使得JVM必须在调用入口点之前实例化一个类.这就是为什么main
是静态的.
我不知道为什么main
总是标记public
.
的main()
在方法C++
,C#
和Java
是静态
因为他们然后可以由运行时引擎调用而不不必实例的任何对象,则代码在身体的main()
将完成剩下的.
这就是Java语言的设计和Java虚拟机的设计和编写方式.
查看第12章执行 - 第12.1.4节调用Test.main:
最后,在完成类Test的初始化之后(在此期间可能发生了其他相应的加载,链接和初始化),调用Test的方法main.
方法main必须声明为public,static和void.它必须接受一个字符串数组的参数.此方法可以声明为
public static void main(String[] args)要么
public static void main(String... args)
查看第2章Java编程语言概念 - 第2.17节执行:
Java虚拟机通过调用某个指定类的方法main并向其传递一个参数(即一个字符串数组)来开始执行.这会导致指定的类被加载(第2.17.2节),链接(第2.17.3节)到它使用的其他类型,并初始化(第2.17.4节).方法main必须声明为public,static和void.
下载并解压缩源jar并查看如何编写JVM,签出../launcher/java.c
,其中包含命令后面的本机C代码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); ... ...
让我们简单地假装,static
不需要作为应用程序入口点.
然后,应用程序类将如下所示:
class MyApplication { public MyApplication(){ // Some init code here } public void main(String[] args){ // real application code here } }
构造函数代码和main
方法之间的区别是必要的,因为在OO中,构造函数应该只确保实例正确初始化.初始化后,该实例可用于预期的"服务".将完整的应用程序代码放入构造函数会破坏它.
所以这种方法会在申请时强制执行三种不同的合同:
有必须是一个默认的构造函数.否则,JVM将不知道要调用哪个构造函数以及应该提供哪些参数.
有必须是一个main
方法1.好的,这并不奇怪.
类不能是abstract
.否则,JVM无法实例化它.
static
另一方面,这种方法只需要一份合同:
必须有main
方法1.
这里既不abstract
是多个构造函数也不重要.
由于Java被设计为用户的简单语言,因此使用一个合同以简单的方式设计应用程序入口点而不是使用三个独立且脆弱的合同以复杂的方式设计也就不足为奇了.
请注意:此参数不是关于JVM内部或JRE内部的简单性.这个论点是关于用户的简单性.
如果不是,如果有多个构造函数应该使用哪个构造函数?
有关Java语言规范中可用的Java程序的初始化和执行的更多信息.
在调用main方法之前,不会实例化任何对象.使用static关键字意味着可以在不首先创建任何对象的情况下调用该方法.
否则,它需要一个要执行的对象的实例.但它必须从头开始调用,而不首先构造对象,因为它通常是main()函数(引导程序)的任务,通常通过使用这些参数/程序参数来解析参数并构造对象.
是什么意思public static void main(String args[])
?
public
是一个访问说明符,意味着任何人都可以访问/调用它,例如JVM(Java虚拟机).
static
允许main()
在创建类的对象之前调用.这是必要的,因为main()
在制作任何对象之前由JVM调用.由于它是静态的,因此可以通过类直接调用它.
class demo { private int length; private static int breadth; void output(){ length=5; System.out.println(length); } static void staticOutput(){ breadth=10; System.out.println(breadth); } public static void main(String args[]){ demo d1=new demo(); d1.output(); // Note here output() function is not static so here // we need to create object staticOutput(); // Note here staticOutput() function is static so here // we needn't to create object Similar is the case with main /* Although: demo.staticOutput(); Works fine d1.staticOutput(); Works fine */ } }
类似地,我们在某些时候对用户定义的方法使用static,这样我们就不需要创建对象了.
void
表示声明的main()
方法不返回值.
String[] args
指定main()
方法中唯一的参数.
args
- 包含类类型对象数组的参数String
.
让我以更简单的方式解释这些事情:
public static void main(String args[])
除applet之外的所有Java应用程序都从它开始执行main()
.
关键字public
是一个访问修饰符,允许从类外部调用该成员.
static
之所以使用是因为它允许main()
在不必实例化该类的特定实例的情况下进行调用.
void
表示main()
不返回任何值.
构建各种类型的小程序,midlet,servlet和bean,然后调用生命周期方法.调用main是对主类所做的所有操作,因此不需要在多次调用的对象中保存状态.将main放在另一个类上是很正常的(虽然不是一个好主意),这会妨碍使用类来创建主对象.
这只是一个惯例,但可能比替代方案更方便.使用静态main,调用Java程序所需要知道的是类的名称和位置.如果它不是静态的,您还必须知道如何实例化该类,或者要求该类具有空构造函数.
如果main方法不是静态的,则需要从程序外部创建主类的对象.你想怎么做?
使用该java
命令执行Java虚拟机(JVM)时,
java ClassName argument1 argument2 ...
执行应用程序时,将其类名指定为java命令的参数,如上所述
JVM尝试调用您指定的类的main方法
- 在这一点上,没有创建类的对象.
声明
main
为静态allows
的JVM到invoke
主without
创建一个instance
类的.
让我们回到命令
ClassName
是一个command-line argument
JVM,它告诉它要执行哪个类.在ClassName之后,您还可以将list of Strings
(由空格分隔)指定为JVM将传递给应用程序的命令行参数.- 这些参数可能用于指定运行应用程序的选项(例如,文件名) - 这就是为什么String[] args
在main中调用了一个参数的原因
参考文献:Java™如何编程(早期对象),第十版