为啥main方法在java中是静态的[重复]

Posted

技术标签:

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

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

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

【问题讨论】:

【参考方案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 如何知道在构造函数重载的情况下调用哪个构造函数,或者即使只有一个参数化构造函数,然后传递什么。”

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

另见:

JLS - Invoke main method

【讨论】:

我希望它使用 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 函数背后的真正原因。

【讨论】:

以上是关于为啥main方法在java中是静态的[重复]的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们允许在 java 中有一个最终的 main 方法?

java中为啥要把main方法定义为一个static方法

为啥主要方法应该是静态的[重复]

java - 为啥main方法没有转换为java中的守护线程[重复]

为啥单例对象创建的scala程序不需要静态main方法?

java新手为啥java类中要有static静态方法?