为什么main方法在java中是静态的

Why main method is static in java

本问题已经有最佳答案,请猛点这里访问。

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

这是正确的原因吗?因为在不进入主函数的情况下,如何创建类的对象?请对此发表看法。如果这不是正确的原因,那么正确的原因是什么?


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

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

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


"Is this reason correct?"

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

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

例如,不存在这样的技术障碍:

1
2
3
4
5
6
 class Hello {
       public void main(String...args){
           System.out.println("Hello, world");

       }
 }

作为一个事实的度量,Java为您创建了一个无ARG构造函数,如果您不指定一个,那么如果包含一个主方法,并且在引擎盖下面创建下面的代码,那么也很容易包括var ARGS构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
 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中使用EDCOX1×2的程序,即"罢工">,但是它会抛出EDOCX1→3 } /罢工。

1
2
3
4
5
6
7
8
9
public class WithoutMain {
    static {
        System.out.println("Look ma, no main!!");
        System.exit(0);
    }
}

$ java WithoutMain
Look ma, no main!!

我知道这不是一种选择,但是,它很有趣,不是吗?


static是一个关键字,当它在main方法之前应用时,jvm会假定这是执行的起点。JavaSuffic给JVM作为通过主()方法输入指定类的责任前任:假设有两类A和B,其中b延伸a,这里,按照Java,对于每一个类,应该创建一个对象来访问该类中的变量和方法,这里在B类静态主()方法中写道,static是word,不管程序启动是什么,它将在程序运行之前为该关键字分配内存。


I have heard some people saying" if main is not static then JVM could create an object of class containing main and call that main through object.

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

But the problem is how JVM knows which constructor to call in case of overloaded constructors or even if there is only one paramaterized constructor, then what to pass."

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

参见:

  • jls-调用主方法


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


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

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

或者,如果没有参数:

1
2
3
4
Component HelloWorld
Export Executable
run() = print"Hello, world!"
end

Java比纯OO语言更实用,具有静态方法、字段和基元类型。其静态主方法更接近C的主函数。你得问戈斯林他为什么选择那个公约。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#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 );
}


main是静态的,因此您的代码可以在不需要先实例化类的情况下执行。也许你甚至不想创建一个类,或者创建类的速度很慢,你想先打印一个"正在加载…"文本,或者你有多个构造函数,等等……有许多原因不强制用户在命令执行开始之前创建类。

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


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

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

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


Java主方法是静态的,Java虚拟机可以在不创建任何包含主方法的类实例的情况下调用它。如果主方法没有声明静态,那么JVM必须创建主类的实例,并且由于构造函数可以重载并且可以有参数,所以JVM在Java中找不到任何确定的方法。


But the problem is how JVM knows which constructor to call in case of overloaded constructors or even if there is only one paramaterized constructor, then what to pass."

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

所以在类中,它不能保证它没有构造函数。同时限制类拥有用户定义的构造函数也是一个坏主意。但是,如果系统允许您编写自己的构造函数,那么即使没有保证它也不会是参数构造函数。所以如果它是一个参数化的构造函数,它不知道要发送什么参数。

所以我认为这就是静态主函数背后的实际原因。