JVM是否在内部实例化抽象类的对象?

kav*_*mre 3 java abstract-class object-construction

我有一个抽象类及其具体的子类,当我创建子类的对象时,它会自动调用超级构造函数.JVM是否在内部创建抽象类的对象?

public abstract class MyAbstractClass {

    public MyAbstractClass() {
        System.out.println("abstract default constructor");
    }

}
public class ConcreteClass extends MyAbstractClass{

    public static void main(String[] args) {
        new ConcreteClass();
    }

}
Run Code Online (Sandbox Code Playgroud)

然后如何在JVM中没有对象的构造函数存在?(如果是抽象类)

构造函数在创建对象后执行,然后不创建抽象类的对象如何执行默认构造函数?(这在Java Doc中提到)

T.J*_*der 6

你不能实例化抽象类是真的吗?

是.

JVM是否在内部创建抽象类的对象?

不,但这是一个常见的误解(这对于它来说不是一种不合理的方式;像JavaScript这样的原型语言就是这样做的).

JVM创建一个对象,该对象属于您创建的类(在您的情况下ConcreteClass).它从superclass(MyAbstractClass)和它的子类()获得了一个对象的方面ConcreteClass,但只有一个对象.

该对象是其所有部分的集合,包括似乎具有相同名称的部分,例如由子类重写的超类的方法.实际上,这些方法具有不同的完全限定名称,并且不会相互冲突,这就是为什么可以调用超类的重写方法的版本.

所以,如果它只是一个对象,为什么你会看到对MyAbstractClass构造函数的调用?在我们回答之前,我需要提一下Java编译器正在做的一些事情,你在源代码中没有看到:

  1. 它正在创建一个默认构造函数ConcreteClass.

  2. 在该构造函数中,它调用MyAbstractClass构造函数.

  3. 为了彻底:在MyAbstractClass构造函数中,它正在添加对超类的(Object)构造函数的super(...)调用,因为在MyAbstractClass构造函数中没有写入调用.

以下是Java编译器为您填写的位添加的代码:

public abstract class MyAbstractClass {

    public MyAbstractClass() {
        super();           // <== The Java compiler adds this call to Object's constructor (#3 in the list above)
        System.out.println("abstract default constructor");
    }

}
public class ConcreteClass extends MyAbstractClass{

    ConcreteClass() {      // <== The Java compiler adds this default constuctor (#1 in the list above)
        super();           // <== Which calls the superclass's (MyAbstractClass's) constructor (#2 in the list above)
    }

    public static void main(String[] args) {
        new ConcreteClass();
    }

}
Run Code Online (Sandbox Code Playgroud)

好吧,尽管如此,让我们在评论中非常有用地提到一点TheLostMind:构造函数不创建对象,而是初始化它们.JVM创建对象,然后根据需要针对该对象运行尽可能多的构造函数(它们实际上应该被称为初始化器),以便为每个超类提供初始化对象部分的机会.

因此,在该代码中,会发生什么(并且您可以在调试器中逐步完成此操作以完全理解它):

  1. JVM创建一个对象

  2. ConcreteClass构造函数被调用

    1. 构造函数做的第一件事是调用它的超类的构造函数,在本例中MyAbstractClass是构造函数.(请注意,这是绝对要求:Java编译器不允许在超类构造函数调用之前在构造函数本身中拥有任何逻辑.)

      1. 构造函数做的第一件事是调用它的超类的构造函数(Object's)

      2. Object构造函数返回时,构造函数的其余部分将MyAbstractClass运行

    2. MyAbtractClass构造函数返回时,构造函数的其余部分将ConcreteClass运行

  3. 该对象作为new ConcreteClass()表达式的结果返回.

请注意,如果存在具有初始化程序的实例字段,则上述内容会变得更复杂.有关完整详细信息,请参阅JLS和JVM规范.