为什么Java的主要方法是静态的?

Java main()方法的方法签名是:

public static void main(String[] args){ ... } 

这种方法是否有静态的原因?

该方法是静态的,因为否则就会有歧义:哪个构造函数应该被调用? 特别是如果你的class级看起来像这样:

 public class JavaClass{ protected JavaClass(int x){} public void main(String[] args){ } } 

JVM应该调用new JavaClass(int)吗? 它应该通过什么?

如果没有,JVM应该实例化JavaClass而不运行任何构造方法? 我认为它不应该,因为这将特殊情况下你的整个class级 – 有时你有一个未初始化的实例,你必须检查每一个可以调用的方法。

有太多的边缘情况和含糊不清的情况让JVM必须在入口点被调用之前实例化一个类。 这就是为什么main是静态的。

我不知道为什么main总是public

这只是惯例。 实际上,甚至名字main()和传入的参数都是纯粹的约定。

在Windows上运行java.exe(或javaw.exe)时,真正发生的是几个Java Native Interface(JNI)调用。 这些调用加载的是真正的JVM的DLL(没错 – java.exe不是JVM)。 当我们必须在虚拟机世界和C,C ++等世界之间build立桥梁时,JNI是我们使用的工具。反过来也是如此 – 至less据我所知是不可能的运行JVM而不使用JNI。

基本上,java.exe是一个超级简单的C应用程序,它parsing命令行,在JVM中创build一个新的String数组来保存这些参数,parsing出包含main()的类名,使用JNI调用来查找main()方法本身,然后调用main()方法,传入新创build的string数组作为参数。 这非常类似于您使用Javareflection时所做的 – 它只是使用易混淆命名的本机函数调用。

编写自己的java.exe版本(源代码与JDK一起发行),并且做一些完全不同的事情是完全合法的。 事实上,这正是我们所有基于Java的应用程序所做的。

我们的每个Java应用程序都有自己的启动器。 我们主要是这样做的,所以我们得到我们自己的图标和进程名称,但是在其他情况下我们想要做一些除了常规的main()调用之外的其他一些事情来派上用场,例如,在一种情况下,我们正在做COM互操作性,我们实际上传递一个COM句柄到main()而不是一个string数组)。

所以,多空:它是静态的原因是B / C,方便。 它被称为“主要”的原因是因为它必须是某种东西,而main()就是他们在C的旧日子里所做的(在那些日子里,这个函数的名字重要的)。 我想,java.exe本来可以让你指定一个完全合格的主要方法名称,而不仅仅是类(java com.mycompany.Foo.someSpecialMain) – 但是这使得IDE更难以自动检测'一个项目中可以启动的课程。

C ++,C#和Java中的main()方法是静态的,因为它们可以被运行时引擎调用,而不必实例化父类的实例。

为什么public static void main(String [] args)?

这就是Java语言的devise和Java虚拟机的devise和编写。

Oracle Java语言规范

检查第12章执行 – 第12.1.4节调用Test.main :

最后,在类Test的初始化完成之后(在此期间可能发生其他相应的加载,链接和初始化),调用Test的main方法。

方法main必须声明为public,static和void。 它必须接受一个单一的参数,这是一个string数组。 这个方法可以被声明为

 public static void main(String[] args) 

要么

 public static void main(String... args) 

Oracle Java虚拟机规范

请参阅第2章Java编程语言概念 – 第2.17节执行 :

Java虚拟机通过调用某个指定类的main方法并将其传递给一个参数(string数组)来开始执行。 这会导致指定的类被加载(§2.17.2),链接(§2.17.3)到它使用的其他types,并被初始化(§2.17.4)。 方法main必须声明为public,static和void。

Oracle OpenJDK源代码

下载并提取源代码jar,看看如何编写JVM,检查出../launcher/java.c ,其中包含命令java [-options] class [args...]后面的本机C代码:

 /* * 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被devise成对用户来说是一种简单的语言因此应用程序入口点也是使用一个合同以简单的方式devise的,而不是用复杂的方式使用三个独立和脆弱的合同。

请注意:这个参数不是关于JVM内部或JRE内部的简单性。 这个论点是关于简单的用户


1这里完整的签名只能算作一个合同。

如果不是,如果有多个构造函数,应该使用哪个构造函数?

有关Java语言规范中可用的Java程序的初始化和执行的更多信息。

否则,将需要执行该对象的一个​​实例。 但是必须从头开始调用,而不必首先构造对象,因为它通常是main()函数(bootstrap)的任务,通常通过使用这些参数/程序参数来parsing参数和构造对象。

在主方法被调用之前,没有对象被实例化。 拥有static关键字意味着可以在不创build任何对象的情况下调用该方法。

public static void main(String args[])是什么意思?

  1. public是一个访问说明符,意味着任何人都可以访问/调用它,例如JVM(Java虚拟机)。
  2. static允许在创build类的对象之前调用main() 。 这是必须的,因为在创build任何对象之前,由JVM调用main() 。 由于它是静态的,它可以通过类直接调用。

     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 */ } } 

    同样,我们在用户定义的方法中使用静态的时候,所以我们不需要创build对象。

  3. void表示声明的main()方法不返回值。

  4. String[] args指定main()方法中唯一的参数。

    args – 一个包含类types为String的对象的数组的参数。

让我以更简单的方式解释这些事情:

 public static void main(String args[]) 

所有的Java应用程序,除了小程序,都从main()开始执行。

关键字public是一个访问修饰符,允许从外部调用成员。

static是因为它允许调用main()而不必实例化该类的特定实例。

void表示main()不返回任何值。

小苹果,midlets,servlets器和各种types的豆被构造,然后有生命周期的方法叫它们。 调用main是对main类所做的所有事情,所以不需要将状态保存在多次调用的对象中。 把主要的东西放在另一个类中是很正常的(虽然不是一个好主意),这会妨碍使用类来创build一个主要的对象。

这只是一个惯例,但可能比替代更方便。 使用一个静态主类,所有你需要知道调用一个Java程序是一个类的名字和位置。 如果它不是静态的,你也必须知道如何实例化这个类,或者要求这个类有一个空的构造函数。

如果main方法不是静态的,你需要从程序外部创build主类的对象。 你想怎么做?

当使用java命令执行Java虚拟机(JVM)时,

 java ClassName argument1 argument2 ... 

当你执行你的应用程序时,你可以将它的类名指定为java命令的参数,如上所述

JVM尝试调用您指定的类的主要方法

在这一点上,没有创build类的对象。

main声明为static allows JVM在without创build类的instanceinvoke main。

让我们回到命令

ClassName是JVM的command-line argument ,告诉它执行哪个类。 在ClassName之后,还可以指定一个list of Strings (用空格分隔)作为JVM传递给应用程序的命令行参数。 这样的参数可以用来指定运行应用程序的选项(例如文件名) – 这就是为什么在主要参数中有一个名为String[] args

参考文献: Java™如何编程(早期对象),第十版

我认为关键字'static'使得main方法成为一个类方法,而class方法只有它的一个副本,可以被所有人共享,而且它不需要一个对象来引用。 所以当编译驱动程序类时,可以调用main方法。 (我只是在Java的字母表级别,抱歉,如果我错了)

main()是静态的,因为; 在应用程序生命周期的这一点上,应用程序堆栈本质上是程序性的,因为没有实例化对象。

这是一个干净的石板。 你的应用程序正在运行,即使没有任何对象被声明(记住,有程序和OO编码模式)。 作为开发人员,您可以通过创build对象实例并根据编译的代码将应用程序转变为面向对象的解决scheme。

面向对象的数百万显而易见的原因是伟大的。 然而,大多数VB开发者在代码中经常使用像“goto”这样的关键字的时代已经过去了。 “goto”是VB中的一个过程命令,它被OO对应的方法调用所取代。

你也可以将静态入口点(main)视为纯粹的自由。 如果Java已经足够用来实例化一个对象,并且只在运行时向你展示这个实例,那么你就没有select,只能编写一个程序化的应用程序。 正如Java听起来那样难以想象,有很多情况需要程序方法。

这可能是一个非常模糊的答复。 请记住,“类”只是一个相关代码的集合。 “实例”是一个孤立的,活生生的,呼吸的自治世代。

原型public static void main(String[])是在JLS中定义的一个约定:

方法main必须声明为public,static和void。 它必须指定一个forms参数(§8.4.1),其声明types是String数组。

在JVM规范5.2中。 虚拟机启动我们可以阅读:

Java虚拟机通过使用引导类加载器(第5.3.1节)创build一个初始类来启动,该初始类是以实现相关的方式指定的。 Java虚拟机然后链接初始类,初始化它,并调用公共类方法void main(String []) 。 这个方法的调用驱动所有进一步的执行。 构成主要方法的Java虚拟机指令的执行可能导致附加的类和接口的链接(并因此产生)以及调用附加的方法。

有趣的是,在JVM规范中没有提到主要方法必须是静态的。 但是该规范还指出,Java虚拟机之前执行两个步骤:

  • 链接最初的类( 5.4。链接 )
  • 初始化它( 5.5。初始化 )

类或接口的初始化由执行其类或接口初始化方法组成。

在2.9。 特殊方法 :

定义了一个类或接口的初始化方法

类或接口最多只有一个类或接口初始化方法,并通过调用该方法进行初始化(第5.5节)。 类或接口的初始化方法具有特殊名称<clinit> ,不带任何参数,并且是无效的。

类或接口的初始化方法不同于以下定义的实例初始化方法

在Java虚拟机的层面上,以Java编程语言(JLS§8.8)编写的每个构造函数都作为一个具有特殊名称<init>的实例初始化方法出现。

所以JVM初始化一个类或接口的初始化方法,而不是实际上是一个构造函数的实例初始化方法 。 所以他们不需要提到主要方法在JVM规范中必须是静态的,因为在调用main方法之前没有创build实例就暗示了这个方法。

最近,类似的问题已经发布在程序员

  • 为什么在Java和C#中的静态主要方法,而不是一个构造函数?

    为了明确Java和C#决定使用静态方法作为入口点,而不是通过Application类的实例来表示应用程序实例,为什么(主要是)Java和C#寻找一个明确的答案,入口点是一个合适的构造函数?

TL; DR部分的接受答案是,

在Java中, public static void main(String[] args)

  1. 高斯林想要
  2. 在C中有经验的人编写的代码(不是J​​ava)
  3. 由在NeWS上运行PostScript的人来执行

http://i.stack.imgur.com/qcmzP.png

对于C#来说,推理过于相似 。 语言devise人员保持熟悉来自Java的程序员的程序入口点语法。 正如C#架构师Anders Hejlsberg所说 ,

…我们使用C#的方法只是为Java程序员提供另一种方法…

这只是一个惯例。 如果这是惯例,JVM当然可以处理非静态的主要方法。 毕竟,你可以在你的类上定义一个静态初始化器,并且在获得你的main()方法之前实例化一个zillion对象。

任何应用程序的真正入口点都是一个静态方法。 如果Java语言支持实例方法作为“入口点”,那么运行时需要在内部实现它作为一个静态方法,该方法构造对象的一个​​实例,然后调用实例方法。

这样一来,我将研究select以下三个选项中的一个特定选项的基本原理:

  1. 我们今天看到的static void main()
  2. 在新构造的对象上调用实例方法void main()
  3. 使用types的构造函数作为入口点(例如,如果入口类被称为Program ,则执行将有效地由new Program() )组成。

分解:

static void main()

  1. 调用封闭类的静态构造函数。
  2. 调用静态方法main()

void main()

  1. 调用封闭类的静态构造函数。
  2. 通过有效地调用new ClassName()构造封闭类的实例。
  3. 调用实例方法main()

new ClassName()

  1. 调用封闭类的静态构造函数。
  2. 构造一个类的实例(然后不做任何事情,只是返回)。

理由:

我将以相反的顺序去做这个。

请记住,Java的devise目标之一是强调(要求尽可能)良好的面向对象编程实践。 在这种情况下,对象的构造函数初始化对象,但不应该对对象的行为负责。 因此,给出new ClassName()的入口点的规范将通过在每个应用程序上强制devise一个“理想”构造函数的例外来混淆新Java开发人员的情况。

通过使main()成为一个实例方法,上面的问题当然就解决了。 然而,它通过要求规范列出入口类的构造函数的签名以及main()方法的签名来创build复杂性。

总之, 指定一个static void main()创build一个复杂性最低的规范,同时遵循将行为放入方法的原则 。 考虑到实现一个main()方法本身构造一个类的实例并调用一个实例方法是非常简单的,指定main()作为一个实例方法并没有真正的优势。

public关键字是一个访问修饰符,它允许程序员控制类成员的可见性。 当一个类成员在public之前时,那个成员可以被声明的类之外的代码访问。

public的对立面是private ,它阻止了一个成员被其他class级以外的代码所使用。

In this case, main() must be declared as public , since it must be called by code outside of its class when the program is started.

The keyword static allows main() to be called without having to instantiate a particular instance of the class. This is necessary since main() is called by the Java interpreter before any objects are made.

The keyword void simply tells the compiler that main() does not return a value.

static – When the JVM makes a call to the main method there is no object that exists for the class being called therefore it has to have static method to allow invocation from class.

Static methods don't require any object. It runs directly so main runs directly.

The static key word in the main method is used because there isn't any instantiation that take place in the main method. But object is constructed rather than invocation as a result we use the static key word in the main method. In jvm context memory is created when class loads into it.And all static members are present in that memory. if we make the main static now it will be in memory and can be accessible to jvm (class.main(..)) so we can call the main method with out need of even need for heap been created.

It is just a convention as we can see here:

The method must be declared public and static , it must not return any value, and it must accept a String array as a parameter. By default, the first non-option argument is the name of the class to be invoked. A fully-qualified class name should be used. If the -jar option is specified, the first non-option argument is the name of a JAR archive containing class and resource files for the application, with the startup class indicated by the Main-Class manifest header.

http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html#description

The public static void keywords mean the Java virtual machine (JVM) interpreter can call the program's main method to start the program (public) without creating an instance of the class (static), and the program does not return data to the Java VM interpreter (void) when it ends.

Source: Essentials, Part 1, Lesson 2: Building Applications

I don't know if the JVM calls main method before the objects are instantiated… But there is far more powerful reason why the main() method is static… When JVM calls the main method of the class (say Person)… it invokes it by " Person.main() " …. You see, the JVM invokes it by the class name. That is why the main() method is supposed to be static and public, so that it can be accessed by the JVM.

Hope it helped… 🙂 … If it did, let me know by commenting..! :d

Basically we make those DATA MEMBERS and MEMBER FUNCTIONS as STATIC which are not performing any task related to an object. And in case of main method, we are making it as an STATIC because it is nothing to do with object, as the main method always run whether we are creating an object or not.

Any method declared as static in Java belongs to the class itself . Again static method of a particular class can be accessed only by referring to the class like Class_name.method_name();

So a class need not to be instantiated before accessing a static method.

So the main() method is declared as static so that it can be accessed without creating an object of that class.

Since we save the program with the name of the class where the main method is present( or from where the program should begin its execution, applicable for classes without a main() method()(Advanced Level)). So by the above mentioned way:

 Class_name.method_name(); 

the main method can be accessed.

In brief when the program is compiled it searches for the main() method having String arguments like: main(String args[]) in the class mentioned(ie by the name of the program), and since at the the beginning it has no scope to instantiate that class, so the main() method is declared as static.

there is the simple reason behind it that is because object is not required to call static method , if It were non-static method, java virtual machine creates object first then call main() method that will lead to the problem of extra memory allocation.