首页 文章

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

提问于
浏览
457

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

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

Is there a reason for this method to be static?

30 回答

  • 36

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

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

  • 3

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

  • 3

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

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

  • 1

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

  • 0

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

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

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

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

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

  • 0

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

  • 3

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

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

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

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

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

  • 30

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

  • 3

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

  • 5

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

    • public 是一个访问说明符,意味着任何人都可以访问/调用它,例如JVM(Java虚拟机) .

    • 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,这样我们就不需要创建对象了 .

    • void 表示声明的 main() 方法未返回值 .

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

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

  • 174

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

    public static void main(String args[])
    

    除applet之外的所有Java应用程序都会开始执行来自 main() .

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

    使用 static 是因为它允许调用 main() 而无需实例化该类的特定实例 .

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

  • 11

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

  • 12

    其背后的原因很简单,因为对象不需要调用静态方法,如果是非静态方法,则java虚拟机首先创建对象然后调用main()方法,这会导致额外的内存分配问题 .

  • 13

    让我们简单地假装,不需要 static 作为应用程序入口点 .

    然后,应用程序类将如下所示:

    class MyApplication {
        public MyApplication(){
            // Some init code here
        }
        public void main(String[] args){
            // real application code here
        }
    }
    

    构造函数代码和 main 方法之间的区别是必要的,因为在OO中,构造函数只能确保实例正确初始化 . 初始化后,该实例可用于预期的"service" . 将完整的应用程序代码放入构造函数会破坏它 .

    所以这种方法会在申请时强制签订不同的 Contract :

    • 必须有默认构造函数 . 否则,JVM将不知道要调用哪个构造函数以及应该提供哪些参数 .

    • 必须有 main 方法1 . 好的,这并不奇怪 .

    • 该课程不得为 abstract . 否则,JVM无法实例化它 .

    另一方面, static 方法只需要 one Contract :

    • 必须有 main 方法1 .

    这里既不是 abstract 也不是多个构造函数 .

    由于Java被设计为用户的简单语言,因此使用 one Contract 以简单的方式设计应用程序入口点并不是使用 three 独立和脆弱的 Contract 以复杂的方式设计也就不足为奇了 .

    请注意:这个参数是 not 关于JVM内部或JRE内部的简单性 . 这个论点是关于 user 的简单性 .


    1完整签名仅计为一份 Contract .

  • 6

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

  • 2

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

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

    • A static void main() 正如我们今天所看到的那样 .

    • 在新构造的对象上调用实例方法 void main() .

    • 使用类型的构造函数作为入口点(例如,如果条目类被称为 Program ,那么执行将实际上由 new Program() 组成) .

    细分:

    static void main()

    • 调用封闭类的静态构造函数 .

    • 调用静态方法 main() .

    void main()

    • 调用封闭类的静态构造函数 .

    • 通过有效调用 new ClassName() 构造封闭类的实例 .

    • 调用实例方法 main() .

    new ClassName()

    • 调用封闭类的静态构造函数 .

    • 构造一个类的实例(然后对它执行任何操作并简单地返回) .

    理由:

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

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

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

    总之, specifying a static void main() creates a specification with the least complexity while adhering to the principle of placing behavior into methods . 考虑到实现一个 main() 方法是多么简单,该方法本身构造一个类的实例并调用一个实例方法,所以没有真正的优势 . 将 main() 指定为实例方法 .

  • 300

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

    java ClassName argument1 argument2 ...
    

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

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

    • 在这一点上,没有创建类的对象 . 将main声明为static允许JVM在不创建类实例的情况下调用main .

    让我们回到命令

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

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

  • 5

    public static void关键字表示Java虚拟机(JVM)解释器可以调用程序的主方法来启动程序(公共)而无需创建类的实例(静态),并且程序不会将数据返回给Java VM解释器(void)结束时 .

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

  • 363

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

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

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

    如果没有,JVM是否应该在不运行任何构造函数方法的情况下实例化 JavaClass ?我认为它不应该被初始化,你必须在每个可以调用的方法中检查它 .

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

    我不知道为什么 main 总是标记为 public .

  • 9

    在Java中声明为static的任何方法都属于类本身 . 同样,只能通过引用像 Class_name.method_name(); 这样的类来访问特定类的静态方法

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

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

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

    Class_name.method_name();
    

    可以访问主要方法 .

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

  • 0

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

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

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

    在Java中,public static void main(String [] args)的原因是Gosling希望由C(非Java)经验的人编写的代码由用于在NeWS for C#上运行PostScript的人执行,这是推理可以说是过渡性的相似 . 语言设计人员为来自Java的程序员保留了程序入口点语法 . 正如C#架构师Anders Hejlsberg所说,......我们使用C#的方法就是为Java程序员提供另一种选择......

  • 0

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

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

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

  • 9

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

    当您运行java.exe(或Windows上的javaw.exe)时,真正发生的是几个Java本机接口(JNI)调用 . 这些调用加载了真正是JVM的DLL(这是正确的 - java.exe不是JVM) . 当我们必须桥接虚拟机世界以及C,C等世界时,JNI是我们使用的工具......反之亦然 - 实际上不可能(至少据我所知) JVM在不使用JNI的情况下运行 .

    基本上,java.exe是一个解析命令的超级简单C应用程序line,在JVM中创建一个新的String数组来保存这些参数,解析出你指定为包含main()的类名,使用JNI调用来查找main()方法本身,然后调用main()方法,传递在新创建的字符串数组中作为参数 . 这非常非常类似于使用Java中的反射时所执行的操作 - 它只是使用容易混淆的命名本机函数调用 .

    编写自己的java.exe版本(源代码随JDK一起发布)并让它完全不同,这对你来说是完全合法的 . 事实上,这正是我们对所有基于Java的应用程序所做的 .

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

    所以,长期和短期:它是静态的原因是b / c,'s convenient. The reason it'被称为'main',它必须是某种东西,而main()就是他们在C的旧时代所做的(当时,这个名字功能很重要) . 我想java.exe可以让你只指定一个完全限定的主方法名,而不仅仅是类(java com.mycompany.Foo.someSpecialMain) - 但这只会让IDE更难以自动检测'launchable'项目中的课程 .

  • 1

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

  • 0

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

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

    Oracle Java语言规范

    查看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虚拟机规范

    查看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来源

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

    原型 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

    class or interface initialization method 定义为:

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

    并且 class or interface initialization methodinstance initialization method 不同,定义如下:

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

    所以JVM初始化 class or interface initialization method 而不是实际上是构造函数的 instance initialization method . 所以他们不会因为没有实例而隐含着这样的事实在调用main方法之前创建 .

  • 1

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

  • 5

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

  • 1

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

  • 0

    C,C#和Java中的main()方法是静态的,因为它们可以由运行时引擎调用,而无需实例化父类的实例 .

相关问题