【问题标题】:Does java internally creates the object of the class which is holding the main method?java是否在内部创建了持有main方法的类的对象?
【发布时间】:2018-12-21 20:06:56
【问题描述】:

我们知道,如果我们想创建 objectobject,我们需要做一些事情:

class MyClass{
// ...
}

为了创建它的object,我们这样做:

MyClass MyObj = new MyClass();

现在,如果我们想在 java 中创建一个程序,我们需要在 class 中有一个 main 方法,并且 class 应该与文件名同名。

例如:

// file MyFile.java
public class MyFile{
    public static void main(String[] args){
      // ...
    }
}

现在的问题是MyFile类的对象是否也会在程序运行时由java在内部创建,以便通过调用main方法开始执行java文件,还是它调用main 方法静态为:

MyFile.main(String[] args);

如果我将MyFile 中的类设置为:

public class MyFile{

    class HelloWorld{
        // ...
    }

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

或具有非静态属性和方法为:

public class MyFile{

    int x = 10;

    public void MyWorld(){
        // ...
    }

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

    int y = 10;

    public void ByeWorld(){
        // ...
    }

}

等等等等

现在,场景是什么? java 会在内部创建MyFile 类的对象吗?在这种情况下java 将执行哪些操作,以便在main 方法的帮助下运行程序以及在main 方法之前和之后加载其他内容?在这些情况下,java 在内部会执行什么操作?

【问题讨论】:

  • Java 编译器不创建对象,而是创建字节码。 Java runtime 根据需要创建对象
  • 方法是static所以属于class而不是类的实例,因此当类被类加载器加载并且不需要实例时可用。

标签: java jvm javac jit


【解决方案1】:

当 JVM 启动时,不会自动创建类的实例。 main 方法只是静态调用的——这就是为什么它首先必须是静态的。

类是初始化的,所以如果你有一个静态初始化器,那个会在main方法之前执行,但是不会构造类的实例.没有必要这样做,它会引入不必要的并发症。 (例如,如果您只包含带参数的构造函数,您会期望发生什么?)

关于JVM启动的更多细节,见chapter 12 of the Java Language Specification

【讨论】:

  • 那么,这是否意味着jvm跳转到public class MyFile{内部并从这里开始执行?不需要创建实例?
  • @SunnyKhan:不,你为什么认为它需要创建一个实例?您无需创建类的实例即可在其他任何地方执行静态方法 - 为什么启动会有所不同?
  • 那么,jvm 从public class MyFile{ 点跳转并开始从这里加载所有成员并在遇到它时触发main 方法,对吗?
  • @SunnyKhan 您似乎将类的定义和初始化与创建该类的实例混淆了。您需要初始化类以调用 main,但不需要该类的实例(因为 main 是静态的)。
  • @SunnyKhan 访问类中的任何内容首先需要加载一个类,使用classloader,通过Java规范定义的详细过程。例如,在加载期间进行安全检查以验证类的完整性。并执行静态初始化程序,如答案中所述。我怀疑你会通过了解类加载过程而感到满意。
【解决方案2】:

除了Jon Skeet's answer,我们可以用一个代码示例来证明在调用main方法时不是创建了封闭类的实例:

public class Test {
    public Test() {
        System.out.println("Test2");
    }

    public static void main(String[] args) {
       System.out.println("Test");
    }
}

这个程序的输出很简单:

Test

如果创建了一个实例,您也会看到Test2 打印到控制台。

【讨论】:

  • Test2 方法需要返回类型void,因此它可以正常工作而不会出现任何错误。
  • @SunnyKhan 这不是方法,它是Test 类的构造函数。
  • 你说得对,我在我的文件中进行测试,其中类名与 Test2 不同,所以它看起来是我的方法,这就是它返回错误的原因。
  • @SunnyKhan 我将班级名称改为Test以避免混淆!
猜你喜欢
  • 2015-04-28
  • 2014-10-10
  • 1970-01-01
  • 2017-09-21
  • 1970-01-01
  • 2016-02-06
  • 2016-12-20
  • 2011-07-13
  • 2013-01-31
相关资源
最近更新 更多