13

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

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

4

9 回答 9

18

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

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

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

于 2010-07-05T17:46:23.970 回答
5

“这个理由对吗?”

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

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

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

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

       }
 }

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

 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 )

顺便说一句,您可以在没有 main 方法Hello! world的情况下使用 Java 程序,但它会抛出java.lang.NoSuchMethodError: main

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

$ java WithoutMain
Look ma, no main!!

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

于 2010-07-05T18:23:34.940 回答
2

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

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

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

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

也可以看看:

于 2010-07-05T17:27:25.153 回答
2

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

于 2010-08-16T12:44:48.717 回答
1

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

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

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

于 2010-07-05T17:27:23.070 回答
1

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

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

于 2010-07-05T17:30:55.393 回答
1

是的,在 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 函数。你得问戈斯林他为什么选择那个大会。

启动 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 );
}
于 2010-07-05T17:50:27.610 回答
1

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

于 2016-03-02T13:47:44.253 回答
0

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

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

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

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

于 2010-07-05T17:36:33.073 回答