为什么Java main方法是静态的?

时间:2008-09-28 19:45:35

标签: java static main

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

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

这种方法是否有理由保持静态?

36 个答案:

答案 0 :(得分:378)

这只是惯例。实际上,即使名称为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'的原因是它必须是某种东西,而main()就是它们在C的旧时代所做的事情(在那些日子里,函数的名称​​ 很重要) 。我想java.exe可以让你只指定一个完全限定的主方法名,而不只是指定类(java com.mycompany.Foo.someSpecialMain) - 但这只会让IDE更难以自动检测'在项目中启动“课程”。

答案 1 :(得分:323)

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

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

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

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

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

我不知道为什么main始终标记为public

答案 2 :(得分:185)

main()C++C#中的Java方法是静态的 因为运行时引擎可以调用它们而不需要实例化任何对象,所以main()正文中的代码将完成其余的工作。

答案 3 :(得分:37)

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

这就是Java语言的设计和Java虚拟机的设计和编写方式。

Oracle Java Language Specification

结帐Chapter 12 Execution - Section 12.1.4 Invoke Test.main

  

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

     

方法main必须声明为public,static和void。它必须接受一个字符串数组的参数。此方法可以声明为

public static void main(String[] args)
     

public static void main(String... args)

Oracle Java Virtual Machine Specification

结帐Chapter 2 Java Programming Language Concepts - Section 2.17 Execution

  

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

Oracle OpenJDK Source

下载并解压缩源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);

... ...

答案 4 :(得分:32)

让我们假装,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内部的简单性,这个论点。这个论点是关于用户的简单性。

<小时/> 1 这里完整的签名仅计为一份合同。

答案 5 :(得分:14)

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

有关Java Language Specification中可用的Java程序的初始化和执行的更多信息。

答案 6 :(得分:12)

在调用main方法之前,不会实例化任何对象。使用static关键字意味着可以在不先创建任何对象的情况下调用该方法。

答案 7 :(得分:12)

因为否则,它需要一个要执行的对象的实例。但它必须从头开始调用,而不首先构造对象,因为它通常是main()函数(引导程序)的任务,解析参数并构造对象,通常使用这些参数/程序参数。

答案 8 :(得分:9)

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

  1. public是一个访问说明符,意味着任何人都可以访问/调用它,例如JVM(Java虚拟机。
  2. static允许在创建类的对象之前调用main()。这是必要的,因为在创建任何对象之前,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 */
        }
    }
    

    同样,我们在某些时候对用户定义的方法使用static,这样我们就不需要创建对象了。

  3. void表示正在声明main()方法 没有返回值。

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

    args - 包含类类型String的对象数组的参数。

答案 9 :(得分:6)

构建各种类型的Applet,midlet,servlet和bean,然后调用生命周期方法。调用main是对主类所做的所有操作,因此不需要在多次调用的对象中保存状态。把main写在另一个类上是很正常的(虽然不是一个好主意),这会妨碍使用类来创建主对象。

答案 10 :(得分:5)

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

答案 11 :(得分:5)

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

答案 12 :(得分:5)

使用java命令

执行Java虚拟机(JVM)时
java ClassName argument1 argument2 ...

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

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

  

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

     

main声明为静态allows JVM为invokewithout创建   该课程的instance

让我们回到命令

ClassName是JVM的command-line argument,它告诉它要执行哪个类。在ClassName之后,您还可以将list of Strings(由空格分隔)指定为JVM将传递给应用程序的命令行参数。 - 这些参数可用于指定运行应用程序的选项(例如,文件名) - 这就是为什么在主

中有一个名为String[] args的参数的原因

参考文献:Java™ How To Program (Early Objects), Tenth Edition

答案 13 :(得分:3)

最近,在Programmers.SE上发布了类似的问题

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

  

在Java中,public static void main(String[] args)的原因是

     
      
  1. Gosling想要
  2.   
  3. 由C(非Java)经验丰富的人编写的代码
  4.   
  5. 由曾经在PostScript
  6. 上运行NeWS的人执行         
        

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

      
         


      对于C#,推理是传递相似的可以这么说。语言设计者保持program entry point语法对于来自Java的程序员来说很熟悉。作为C#架构师Anders Hejlsberg puts it

         
        

    ...我们使用C#的方法就是为Java程序员提供另一种选择......

      
         

    ...

答案 14 :(得分:3)

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

  

方法main必须声明为public,static和void。它必须指定一个形式参数(第8.4.1节),其声明的类型是String数组。

在JVM规范5.2. Virtual Machine Start-up 中,我们可以阅读:

  

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

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

  

类或接口的初始化包括执行其类或接口初始化方法。

2.9. Special Methods中:

定义类或接口初始化方法

  

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

类或接口初始化方法实例初始化方法的定义不同,如下所示:

  

在Java虚拟机的级别上,使用Java编程语言(JLS§8.8)编写的每个构造函数都显示为具有特殊名称<init>的实例初始化方法。

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

答案 15 :(得分:3)

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

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

面向对象非常适合数百万个显而易见的原因。然而,大多数VB开发人员经常在其代码中使用“goto”等关键字的日子已经过去了。 “goto”是VB中的一个过程命令,它被其OO副词:方法调用替换。

您还可以将静态入口点(main)看作纯粹的自由。如果Java已经足够不同来实例化一个对象并且在运行时只向你呈现该实例,那么你就没有选择但是编写一个程序性应用程序。正如Java听起来难以想象的那样,有很多场景需要采用程序方法。

这可能是一个非常模糊的回复。请记住,“class”只是相互关联的代码的集合。 “实例”是一个孤立的,生活和呼吸的自主一代。

答案 16 :(得分:3)

我认为关键字'static'使main方法成为一个类方法,而类方法只有一个副本,并且可以被所有人共享,而且,它不需要一个对象供参考。因此,在编译驱动程序类时,可以调用main方法。 (我只是在java的字母级别,对不起,如果我错了)

答案 17 :(得分:2)

public关键字是一个访问修饰符,允许程序员控制 班级成员的知名度。当一个类成员前面有public时,那就是那个 成员可以通过声明它的类之外的代码访问。

public的反面是private,它阻止成员被其类外部定义的代码使用。

在这种情况下,main()必须声明为public,因为必须调用它 程序启动时,通过其类外的代码。

关键字static允许 无需实例化类的特定实例即可调用main()。这是必要的,因为在创建任何对象之前,Java解释器会调用main()

关键字void只是告诉编译器main()没有返回值。

答案 18 :(得分:2)

这只是一个惯例。如果这是惯例,JVM当然可以处理非静态主方法。毕竟,您可以在类上定义静态初始化程序,并在进入main()方法之前实例化zillion对象。

答案 19 :(得分:1)

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

有了这个,我将检查选择以下三个选项中特定一个的理由:

  1. 我们今天看到的static void main()
  2. 调用新构造对象的实例方法void main()
  3. 使用类型的构造函数作为入口点(例如,如果条目类被调用Program,则执行实际上将由new Program()组成)。
  4. 故障:

    static void main()

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

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

        1. 调用封闭类的静态构造函数。
        2. 构造一个类的实例(然后对它做任何事情并简单地返回)。
        3. 理由:

          我将以相反的顺序执行此操作。

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

          通过使main()成为实例方法,上述问题肯定已经解决了。但是,它要求规范列出条目类的构造函数的签名以及main()方法的签名,从而产生复杂性。

          总之,指定static void main()会创建一个复杂性最低的规范,同时遵循将行为放入方法的原则。考虑到实现一个main()方法是多么简单,它本身构造一个类的实例并调用一个实例方法,将main()指定为实例方法没有任何实际好处。

答案 20 :(得分:1)

static - 当JVM调用main方法时,没有对象被调用,因此它必须有静态方法来允许从类调用。

答案 21 :(得分:1)

我不知道JVM是否在实例化对象之前调用main方法...但是有一个更强大的原因,为什么main()方法是静态的...当JVM调用main方法时上课(比方说,人)。它通过“ Person.main()”调用它。你看,JVM通过类名调用它。这就是为什么main()方法应该是静态的和公共的,以便JVM可以访问它。

希望它有所帮助。如果有,请通过评论告诉我。

答案 22 :(得分:0)

main方法始终需要是静态的,因为在运行时JVM不会创建任何对象来调用main方法,并且正如我们在Java中所知,static方法是可以使用类名调用的唯一方法,因此main方法始终需要是静态的

有关更多信息,请访问以下视频:https://www.youtube.com/watch?v=Z7rPNwg-bfk&feature=youtu.be

答案 23 :(得分:0)

这只是一个惯例,我们可以在这里看到:

  

方法必须声明为public和static ,它不能返回任何方法   值,它必须接受一个String数组作为参数。默认情况下,   第一个非选项参数是要调用的类的名称。   应使用完全限定的类名。如果-jar选项是   如果指定,则第一个非选项参数是JAR存档的名称   包含应用程序的类和资源文件   Main-Class清单标题指示的启动类。

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

答案 24 :(得分:0)

  

public static void keywords意味着Java虚拟机(JVM)解释器可以调用程序的main方法来启动程序(公共),而无需创建类的实例(静态),并且程序不会返回数据结束时的数据到Java VM解释器(void)。

来源: Essentials, Part 1, Lesson 2: Building Applications

答案 25 :(得分:0)

来自java.sun.com(网站上有更多信息):

  

main方法是静态的,为Java VM解释器提供了一种启动类的方法,而无需先创建控件类的实例。程序启动后,在main方法中创建控件类的实例。

我的理解一直只是主要方法,就像任何静态方法一样,可以在不创建关联类的实例的情况下调用,允许它在程序中的任何其他内容之前运行。如果它不是静态的,你必须在调用它之前实例化一个对象 - 这会产生'鸡和鸡蛋'问题,因为main方法通常是你在程序开始时用来实例化对象的。

答案 26 :(得分:0)

静态方法不需要任何对象。它直接运行,因此直接运行。

答案 27 :(得分:0)

使用main方法中的静态关键字,因为main方法中没有任何实例化。 但是对象是构造而不是调用,因此我们在main方法中使用静态关键字。 在jvm上下文中,当类加载到内存中时会创建内存。所有静态成员都存在于该内存中。如果我们现在使main为静态,它将在内存中并且可以被jvm(class.main(..))访问,因此我们可以调用main方法,甚至不需要创建堆。

答案 28 :(得分:0)

在Java中声明为static的任何方法都属于类本身。 同样,只能通过引用像Class_name.method_name();

这样的类来访问特定类的静态方法

因此,在访问静态方法之前,不需要实例化类。

因此main()方法被声明为static,因此可以在不创建该类对象的情况下访问它。

因为我们使用main方法所在的类的名称(或者程序应该从哪里开始执行)保存程序,适用于没有main()方法()(高级)的类。所以通过上面提到的方式:

Class_name.method_name();

可以访问主要方法。

简而言之,当编译程序时,它会在所提及的类中(即通过程序名称)搜索main()方法,其中包含Stringmain(String args[])个参数,并且在开头它没有实例化该类的范围,因此main()方法被声明为static。

答案 29 :(得分:0)

基本上我们将那些数据成员和成员函数设置为STATIC,它们不执行任何与对象相关的任务。在main方法的情况下,我们将它作为STATIC,因为它与object无关,因为无论我们是否创建对象,main方法总是运行。

答案 30 :(得分:0)

背后有一个简单的原因是因为对象不需要调用静态方法,如果是非静态方法,则java虚拟机首先创建对象然后调用main()方法,这将导致额外的问题记忆分配。

答案 31 :(得分:0)

程序的主要方法具有保留字 静态,这意味着允许在静态上下文中使用它。上下文涉及在程序运行期间计算机存储器的使用。当虚拟机加载程序时,它会为其创建静态上下文,分配计算机内存来存储程序及其数据等。动态上下文是某种类型在程序运行期间稍后进行的内存分配。如果不允许在静态上下文中运行main方法,程序将无法启动。

答案 32 :(得分:-1)

static表示此方法是类方法。并且在不需要任何类对象的情况下调用它。

答案 33 :(得分:-1)

由于main()和java的程序的执行开始是纯粹面向对象的程序,其中对象在main()中声明,这意味着在创建对象之前调用main(),所以如果main()不是静态的那么要调用它就需要一个对象,因为静态意味着不需要对象..........

答案 34 :(得分:-1)

这是一个经常被问到的问题,为什么main()在Java中是静态的。

回答:我们知道在Java中,执行是从JVM的main()开始的。当JVM在那时执行main()时,包含main()的类没有实例化,因此我们不能在没有引用它的对象的情况下调用非静态方法。因此,为了调用它,我们将其设置为静态,因为类加载器会在JVM上下文内存空间中加载JVM可以直接调用它们的所有静态方法。

答案 35 :(得分:-3)

因为,静态成员不是任何特定类的一部分,而主要方法不需要创建其Object,但仍然可以引用所有其他类。