Java main()方法的方法签名为:
public static void main(String[] args){
...
}
此方法是否有理由是静态的?
Java main()方法的方法签名为:
public static void main(String[] args){
...
}
此方法是否有理由是静态的?
Answers:
该方法是静态的,因为否则会产生歧义:应调用哪个构造函数?特别是如果您的班级看起来像这样:
public class JavaClass{
protected JavaClass(int x){}
public void main(String[] args){
}
}
JVM应该调用new JavaClass(int)
吗?它应该做什么x
?
如果不是,JVM是否应在JavaClass
不运行任何构造方法的情况下实例化?我认为不应该这样做,因为这会使整个类成为特殊情况-有时您有一个尚未初始化的实例,并且必须在每个可以调用的方法中进行检查。
对于JVM来说,在进入入口点之前必须实例化一个类的情况,边缘情况和歧义太多了。这就是为什么main
是静态的。
我不知道为什么main
总是被标记public
。
public static void main
用作入口点的标记–公共的无参数构造函数不会大喊“这可能是入口点!” 以同样的方式。
main
要调用的决策,存在相同的“问题” 。奇怪的是(对您而言),JVM可以很好地进行管理。
这只是约定。实际上,即使名称main()和传入的参数也完全是约定俗成的。
当您运行java.exe(或Windows上的javaw.exe)时,实际上发生了几次Java本机接口(JNI)调用。这些调用将加载真正是JVM的DLL(是的-Java.exe不是JVM)。JNI是我们在桥接虚拟机世界以及C,C ++等世界时使用的工具。反之亦然-至少(据我所知)不可能真正获得JVM在不使用JNI的情况下运行。
基本上,java.exe是一个超级简单的C应用程序,它解析命令行,在JVM中创建一个新的String数组来保存这些参数,解析出指定为包含main()的类名,使用JNI调用来查找main()方法本身,然后调用main()方法,将新创建的字符串数组作为参数传入。这非常类似于使用Java反射时的操作-它只是使用容易混淆的命名本机函数调用。
编写自己的版本的java.exe(源代码随JDK分发)并让它执行完全不同的操作,这是完全合法的。实际上,这正是我们对所有基于Java的应用程序所做的事情。
我们每个Java应用程序都有自己的启动器。我们主要这样做是为了获得自己的图标和进程名称,但是在其他情况下,除了常规的main()调用之外,我们还想做些其他事情以方便处理(例如,在一种情况下, COM互操作性,我们实际上将COM句柄传递给main()而不是字符串数组)。
所以,总之,短期:它是静态的原因是方便的b / c。之所以称其为“ main”,是因为它必须是某种东西,而main()就是他们在C的早期(当时的函数名称很重要)所做的事情。我想java.exe可以允许您只指定一个完全限定的主方法名称,而不是仅指定类(java com.mycompany.Foo.someSpecialMain)-但这使IDE很难自动检测“项目中的“可启动”类。
java.exe
)
static
在main()
声明只是常规的缘故。它是'main()'而不是其他东西的事实是可行的。
main
非静态的,并且仍在该语言的范围之内。在不征求设计师意见的情况下,我们只需要同意不同意。:)
的main()
在方法C++
,C#
和Java
是静态
因为他们然后可以由运行时引擎调用而不不必实例的任何对象,则代码在身体的main()
将完成剩下的。
public static void main...
,为什么不能约定应用程序入口点类应具有公共默认构造函数?
static void main
要调用的重载?完全没有问题。
static
诸如此类的方法main
经常用于new
创建这样的对象。
这就是设计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)
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);
... ...
main
不是静态的,则意味着必须知道类实例状态,并且定义起来要复杂得多,例如首先使用哪个构造函数。
public static void main(String arguments[])
-参考:Oak 0.2 Spec。
Runnable
。以相同的方式(即具有Runnable.Run
入口点)表示整个过程在Java中绝对有意义。当然,Runnable
它本身可以说是设计缺陷,这是由于Java还没有匿名方法引起的。但是既然已经在那里……
让我们简单地假装,这static
不是应用程序入口点所必需的。
应用程序类将如下所示:
class MyApplication {
public MyApplication(){
// Some init code here
}
public void main(String[] args){
// real application code here
}
}
构造函数代码和main
方法之间的区别是必要的,因为在OO中,构造函数仅应确保实例已正确初始化。初始化后,该实例可用于预期的“服务”。将完整的应用程序代码放入构造函数中会破坏这一点。
因此,此方法将在应用程序上强制使用三个不同的合同:
main
方法1。好的,这并不奇怪。abstract
。否则,JVM无法实例化它。static
另一方面,该方法仅需要一个合同:
main
方法1。在这里,abstract
构造函数都不重要。
由于Java被设计为对用户来说是一种简单的语言,因此毫不奇怪,应用程序入口点也已经以一种简单的方式使用一个合约来设计,而不是以复杂的方式使用三个独立且脆弱的合约来设计。
请注意:此参数与JVM或JRE内部的简单性无关。这个论点是关于用户的简单性。
main
是方法public
,static
以及具有签名void main(String[])
。我同意,如果该方法是一个实例方法中,JRE将有略微更多的工作,但这类工作将是相同的,而不是复杂性较高显著(见前面的回答的意见的讨论)。我不认为这种差异说明了将入口点设为静态的决定,尤其是因为存在解决实例方法所需的方法并且易于使用。
static public main(String[])
方法是一个签名,因此是一个合同。否则,必须遵循三个独立的合同。
Runnable
。显然,Java希望开发人员始终遵守该合同,为什么对于应用程序入口点而言,合同费用太高?这是没有意义的。
Thread
和 Runnable
案件没有什么是对用户隐藏,他可以清楚地看到发生了什么事情,他必须实现的变化只有那些适合他的合同-他是在控制,而不是系统。
是什么意思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
。
这只是一个约定,但可能比其他方法更方便。使用静态主程序,调用Java程序所需要做的就是知道类的名称和位置。如果不是静态的,则还必须知道如何实例化该类,或要求该类具有空的构造函数。
使用java
命令执行Java虚拟机(JVM)时,
java ClassName argument1 argument2 ...
执行应用程序时,如上所述,将其类名称指定为java命令的参数。
JVM尝试调用您指定的类的main方法
—至此,尚未创建该类的对象。
将JVM 声明
main
为静态allows
以invoke
主要without
创建instance
类。
让我们回到命令
ClassName
是command-line argument
JVM的,它告诉它要执行哪个类。在ClassName之后,还可以指定list of Strings
JVM将传递给您的应用程序的命令行参数(用空格分隔)。-此类参数可能用于指定选项(例如文件名)来运行应用程序-这就是为什么String[] args
在main中调用一个参数的原因
最近,类似的问题已发布在Programmers.SE上
寻找一个主要或次要来源的明确答案,为什么Java和C#决定将静态方法作为其入口点-而不是通过
Application
类的实例表示应用程序实例,而入口点是合适的构造函数?
TL; DR接受的答案的一部分是,
在Java中,原因
public static void main(String[] args)
是
- 高斯林通缉
- 由具有C语言(不是Java)经验的人编写的代码
- 由曾经在NeWS上运行PostScript的人执行
对于C#来说,推理在传递上是相似的。语言设计者使Java程序员熟悉程序入口点语法。正如C#架构师Anders Hejlsberg所说,...我们使用C#的方法只是为Java程序员提供了替代方案...
...
main()是静态的,因为;在应用程序生命周期的这一点上,由于还没有实例化对象,因此应用程序堆栈本质上是过程性的。
这是一块干净的石板。此时,即使没有声明任何对象,您的应用程序仍在运行(请记住,存在过程和OO编码模式)。您作为开发人员,可以通过创建对象实例并根据其中编译的代码将应用程序转换为面向对象的解决方案。
面向对象之所以伟大,有数百万个显而易见的原因。但是,大多数VB开发人员在其代码中定期使用诸如“ goto”之类的关键字的日子已经一去不复返了。“ goto”是VB中的一个过程命令,由其OO对应项:方法调用代替。
您也可以将静态入口点(main)视为纯粹的自由。如果Java具有足够的差异来实例化一个对象,并且仅在运行时向您呈现该实例,那么您将没有选择但是要编写一个过程应用程序。对于Java来说,这是难以想象的,但可能有许多场景需要过程方法。
这可能是一个非常模糊的答复。记住,“类”只是相互关联的代码的集合。“实例”是该类孤立,生活和呼吸自发的一代。
main
达到之前先实例化许多对象。并且,如果在包含main的类中包含静态构造函数,则该构造函数也将main
同样执行。
原型public static void main(String[])
是JLS中定义的约定:
方法main必须声明为public,static和void。它必须指定一个声明的类型为String数组的形式参数(第8.4.1节)。
在JVM规范5.2中。虚拟机启动我们可以阅读:
Java虚拟机通过使用引导类加载器(第5.3.1节)创建一个初始类来启动,该类以与实现相关的方式指定。然后,Java虚拟机将链接初始类,对其进行初始化,然后调用公共类方法void main(String [])。该方法的调用驱动所有进一步的执行。构成主要方法的Java虚拟机指令的执行可能导致其他类和接口的链接(并因此创建),以及其他方法的调用。
有趣的是,在JVM规范中,没有提到main方法必须是静态的。但是规范还说Java虚拟机在执行以下两个步骤之前:
类或接口的初始化包括执行其类或接口的初始化方法。
在2.9。特殊方法:
定义了一个类或接口的初始化方法:
一个类或接口最多具有一个类或接口初始化方法,并通过调用该方法进行初始化(第5.5节)。类或接口的初始化方法具有特殊名称
<clinit>
,不带任何参数,并且是无效的。
并且类或接口的初始化方法与实例初始化方法的不同之处如下:
在Java虚拟机级别,使用Java编程语言(JLS§8.8)编写的每个构造函数都将显示为具有特殊名称的实例初始化方法
<init>
。
因此,JVM初始化类或接口初始化方法,而不初始化实际上是构造函数的实例初始化方法。因此,他们无需提及JVM规范中main方法必须是静态的,这是因为在调用main方法之前没有创建任何实例这一事实暗示了这一点。
任何应用程序的真正入口都是静态方法。如果Java语言支持将实例方法作为“入口点”,则运行时将需要在内部将其实现为静态方法,该方法构造对象的实例,然后调用该实例方法。
鉴于此,我将研究选择以下三个选项之一的基本原理:
static void main()
像今天我们看到它。void main()
在新构造的对象上调用的实例方法。Program
,则执行将有效地由组成new Program()
)。static void main()
main()
。void main()
new ClassName()
。main()
。new ClassName()
我将按照相反的顺序进行操作。
请记住,Java的设计目标之一是强调(尽可能要求)良好的面向对象编程实践。在这种情况下,对象的构造函数将初始化该对象,但不应对该对象的行为负责。因此,给出了一个切入点的规范new ClassName()
将在每个应用程序上强制“理想”构造函数的设计例外,从而使新的Java开发人员困惑。
通过创建main()
实例方法,可以解决上述问题。但是,它要求规范列出条目类的构造函数的签名以及main()
方法的签名,从而增加了复杂性。
总之,指定a static void main()
会创建最复杂的规范,同时遵守将行为放入方法的原则。考虑到实现一个main()
本身构造一个类的实例并调用一个实例方法的方法有多简单,将其指定main()
为实例方法并没有真正的优势。
main
。main
对于初学者来说过于复杂的理由似乎令人难以置信。事实上,静态main
是非常适合初学者混乱,我怀疑一个构造函数会更如此。您说“构造函数不应对对象的行为负责”。这听起来很有趣,但我不确定是否会同意。为什么不呢?是什么阻止了这种情况?
静态-当JVM调用main方法时,被调用的类不存在任何对象,因此它必须具有静态方法以允许从类进行调用。
我不知道JVM是否在实例化对象之前调用了main方法...但是main()方法是静态的却有更强大的原因...当JVM调用类的main方法时(例如,人)。它通过“ Person.main() ” 来调用它。您会看到,JVM通过类名调用它。这就是为什么main()方法应该是静态且公共的,以便JVM可以访问它的原因。
希望能有所帮助。如果有,请通过评论让我知道。
正如我们在这里看到的那样,这只是一个约定:
该方法必须声明为public和static,它不能返回任何值,并且必须接受String数组作为参数。默认情况下,第一个非选项参数是要调用的类的名称。应该使用标准的类名。如果指定了-jar选项,则第一个非选项参数是JAR归档文件的名称,其中包含应用程序的类和资源文件,且启动类由Main-Class清单标头指示。
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html#description
public static void关键字意味着Java虚拟机(JVM)解释器可以调用程序的main方法来启动程序(公共),而无需创建类的实例(静态),并且程序不会将数据返回给Java VM解释器(无效)何时结束。
基本上,我们将那些不执行任何与对象相关的任务的数据成员和成员函数设为静态。在使用main方法的情况下,我们将其作为STATIC,因为它与对象无关,因为main方法始终在运行,无论我们是否创建对象。
Java中声明为static的任何方法都属于该类本身。同样,只能通过引用类似的类来访问特定类的静态方法Class_name.method_name();
因此,在访问静态方法之前无需实例化类。
因此main()方法声明为,static
因此无需创建该类的对象即可对其进行访问。
由于我们使用存在主方法的类的名称(或程序应从其开始执行的位置)保存该程序的名称,因此适用于不带main()
method()(高级)的类。因此,通过上述方式:
Class_name.method_name();
可以访问main方法。
简而言之,在编译程序时,它会在所提及的类中搜索main()
具有以下String
参数的方法:(main(String args[])
在程序的名称中),并且由于在开始时就没有实例化该类的范围,因此main()方法被声明为静态。
从java.sun.com(网站上有更多信息):
main方法是静态的,为Java VM解释器提供了一种启动类的方式,而无需先创建控件类的实例。程序启动后,将在main方法中创建控件类的实例。
我的理解一直很简单,就像调用任何静态方法一样,可以在不创建关联类实例的情况下调用main方法,从而使它可以在程序中的其他任何对象之前运行。如果不是静态的,则必须在调用它之前实例化一个对象,这会产生“鸡和蛋”的问题,因为通常在程序开始时主要使用main方法来实例化对象。
Runnable
Java中看似相似的对象(线程,通过)确实使用了这种设计。为什么这里有(明显的)例外?