【问题标题】:Why main method is static in java [duplicate]为什么main方法在java中是静态的[重复]
【发布时间】:2011-03-12 00:09:24
【问题描述】:

我听到有人说“如果 main 不是静态的,那么 JVM 可以创建一个对象 包含 main 的类并通过对象调用该 main。
但问题是 JVM 如何知道在构造函数重载的情况下调用哪个构造函数,或者即使只有一个参数化构造函数,然后传递什么。”

这是正确的原因吗?
因为不进入主函数怎么创建类的对象呢?
请就此发表您的看法。如果这不是正确的原因,那么正确的原因是什么?

【问题讨论】:

    标签: java static main


    【解决方案1】:

    这只是一个约定。 Java 语言设计者可以很容易地决定您必须指定一个要实例化的类,使其构造函数成为主要方法。但是调用静态方法同样有效,并且不需要先实例化一个类。

    另外,如果该类有一个超类,您可以通过更改超类来改变程序启动的行为(因为必须在子类之前调用​​超类构造函数),这可能是无意的。静态方法没有这个问题。

    主要方法是静态的,因为它使事情变得更简单,但如果他们想让它更复杂,他们可以做到。

    【讨论】:

    • Java以C为蓝本,Java的“main”概念与C的“main”概念非常接近。
    【解决方案2】:

    “这个理由对吗?”

    在某种程度上是这样,尽管从未如此具体地解释过。

    我们可以约定也使用String...args 调用构造函数,这意味着您至少需要一个对象来运行,但(可能)设计者认为不需要。

    例如,有这样的东西没有技术障碍:

     class Hello {
           public void main(String...args){
               System.out.println("Hello, world");
    
           }
     }
    

    事实上,Java 会为你创建一个无参数构造函数,如果你不指定一个,那么也很容易包含一个 var args 构造函数,如果该类包含一个 main 方法,并在下创建引擎盖下面的代码:

     class Hello {
          // created by the compiler
          public Hello(){}
          public Hello( String ... args ) {
              this();
              main( args );
          }
          // end of code created by the compiler
          public void main( String ... args ) {
               System.out.println("Hello, world!");
          }
      }
    

    但这会创建不需要的代码,以及额外分配的对象,在这种情况下不会做任何事情;两个构造函数(而不是一个)等等。最后它看起来太神奇了。

    取决于语言设计者。在这种情况下,他们可能认为不这样做会更简单,只需验证调用的类是否具有称为public static void main( String [] args )的方法的特殊签名

    顺便说一句,您可以在 Java 中使用 Hello! world 程序 without main method但它会抛出 java.lang.NoSuchMethodError: main

    public class WithoutMain {
        static {
            System.out.println("Look ma, no main!!");
            System.exit(0);
        }
    }
    
    $ java WithoutMain
    Look ma, no main!!
    

    我知道这不是一个替代方案,但有趣的是不是吗?

    【讨论】:

      【解决方案3】:

      我听说有人说“如果 main 不是静态的,那么 JVM 可以创建一个包含 main 的类的对象并通过对象调用该 main。

      这不是真的。至少,这在JLS 中没有指定。

      但问题是 JVM 如何知道在构造函数重载的情况下调用哪个构造函数,或者即使只有一个参数化构造函数,然后传递什么。”

      如果是真的,我只希望它调用(隐式)默认的无参数构造函数。

      另见:

      【讨论】:

      • 我希望它使用 this(String... args) 构造函数。
      • 好的..我只是想问一下JVM是否有可能在任何情况下创建一个包含main的类对象?如果可以创建对象,是否可以通过它调用main?请举个例子。
      • (几乎)一切皆有可能。但是 JVM 目前没有这样做,jvm/java 规范也没有说应该这样做。
      • 不,它没有。您需要您自己(在main() 方法中)完成。
      • @Pete:我根据 JLS 给出了答案。责备我,因为这在技术上并非不可能,老实说没有意义:)
      【解决方案4】:

      static是一个关键字,当它应用在main方法之前时,JVM会假设这是执行的起点。所以你的JVM是这样想的吗? java软人赋予JVM负责通过main()方法进入指定类 前任: 假设有两个类 A 和 B, 其中 B 扩展 A, 这里根据java,对于每个类都应该创建一个对象来访问该类中的变量和方法,这里在B类中编写了静态main()方法,静态是单词,不管程序执行是否开始......它将被分配程序执行前该关键字的内存。

      【讨论】:

        【解决方案5】:

        因为它可能有主要方法。并且因为主要对象不需要是对象。如果是,则需要实例化一个。

        如果你自己使用jvm.dll,你不需要main函数,只需创建一个对象并调用它。

        但是,通过这种方式,可以进行非面向对象的编程,只是为了那些出于某种原因需要它的人。 :)

        【讨论】:

          【解决方案6】:

          main 是静态的,因此您的代码无需先实例化类即可执行。也许您甚至不想创建一个类,或者创建类很慢并且您想先打印出“正在加载...”文本,或者您有多个构造函数等...有很多原因不强制用户在开始执行命令之前创建一个类。

          如果您静态创建对象,您仍然可以在执行 main() 之前创建对象。

          【讨论】:

            【解决方案7】:

            是的,在 JVM 上运行的其他语言会创建对象或模块(它们也是对象)并运行它们。例如,堡垒语言“Hello world”看起来像

            Component HelloWorld
            Export Executable
            run(args) = print "Hello, world!"
            end
            

            或者,没有参数:

            Component HelloWorld
            Export Executable
            run() = print "Hello, world!"
            end
            

            Java 比纯 OO 语言更实用一些,它具有静态方法和字段以及原始类型。它的静态 main 方法更接近于 C 的 main 函数。您将不得不询问 Gosling 他为什么选择该公约。

            启动 JVM 的代码相当简单 - 这个例子创建了一个 JVM,创建了一个对象并使用命令行参数调用它的 run 方法 - 使启动函数 (new main.HelloWorld()).run(args) 而不是 main.HelloWorld.main(args)

            #include <stdio.h>
            #include <jni.h>
            
            JNIEnv* create_vm() {
                JavaVM* jvm;
                JNIEnv* env;
                JavaVMInitArgs args;
                JavaVMOption options[1];
            
                args.version = JNI_VERSION_1_2;
                args.nOptions = 1;
            
                options[0].optionString = "-Djava.class.path=C:\\java_main\\classes";
                args.options = options;
                args.ignoreUnrecognized = JNI_TRUE;
            
                JNI_CreateJavaVM(&jvm, (void **)&env, &args);
            
                return env;
            }
            
            int invoke_class(JNIEnv* env, int argc, char **argv) {
                jclass helloWorldClass;
            
                helloWorldClass = env->FindClass("main/HelloWorld");
            
                if (helloWorldClass == 0)
                    return 1;
            
                jmethodID constructorMethod = env->GetMethodID(helloWorldClass, "<init>", "()V");
            
                jobject object = env->NewObject(helloWorldClass, constructorMethod);
            
                if (object == 0)
                    return 1;
            
                jobjectArray applicationArgs = env->NewObjectArray(argc, env->FindClass("java/lang/String"), NULL);
            
                for (int index = 0; index < argc; ++index) {
                    jstring arg = env->NewStringUTF(argv[index]);
                    env->SetObjectArrayElement(applicationArgs, index, arg);
                }
            
                jmethodID runMethod = env->GetMethodID(helloWorldClass, "run", "([Ljava/lang/String;)V");
            
                env->CallVoidMethod(object, runMethod, applicationArgs);
            
                return 0;
            }
            
            int main(int argc, char **argv) {
                JNIEnv* env = create_vm();
            
                return invoke_class( env, argc, argv );
            }
            

            【讨论】:

              【解决方案8】:

              不需要创建对象来调用静态方法。所以jvm不需要分配额外的内存来创建main的obj然后调用它。

              【讨论】:

                【解决方案9】:

                但问题是 JVM 如何知道在构造函数重载的情况下调用哪个构造函数,或者即使只有一个参数化构造函数,然后传递什么。”

                我也这么认为。我不使用Java。我使用 C++。如果您不自己编写构造函数,则默认为您提供无参数构造函数和复制构造函数。但是当您自己编写构造函数时,编译器不会提供构造函数。我认为 Java 也遵循了这个理论。

                所以在一个类中它不能保证它不会有一个构造函数。还限制类具有用户定义的构造函数是一个坏主意。但是,如果系统允许您编写自己的构造函数,那么即使不能保证它将是无参数构造函数。所以如果是带参数的构造函数就不知道要送什么参数了。

                所以我认为这就是静态 Main 函数背后的真正原因。

                【讨论】:

                  猜你喜欢
                  • 2016-05-30
                  • 2012-12-28
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-10-27
                  • 2020-12-17
                  • 1970-01-01
                  • 2011-12-11
                  • 1970-01-01
                  相关资源
                  最近更新 更多