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

11 浏览
0 Comments

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

我有一个抽象类和它的具体子类,当我创建子类的对象时,它自动调用超类的构造函数。JVM是否在内部创建了抽象类的对象?\n然后在JVM中,构造函数是如何在没有对象的情况下存在的?(对于抽象类的情况)\n此外,在创建抽象类的对象之前,如何执行默认构造函数?(这在Java文档中有提到)

0
0 Comments

JVM内部是否为抽象类实例化一个对象?

抽象类是一种不能被实例化的类。在调用构造函数时,对象会被创建,但是这取决于类是抽象类还是具体类。只有具体类才会创建对象,而无法使用new关键字显式地创建抽象类的实例。

JVM也不会创建抽象类的实例。注意,类对象会被创建,但是抽象类的实例不会被创建。

那么,在抽象类中如何存在构造函数而没有对象呢?

JVM在堆中创建一个空对象,其中包含空字段,具体类和抽象类的构造函数都负责初始化自己类的字段。

0
0 Comments

问题的出现的原因:

JVM在实例化一个抽象类时不会创建对象,而是调用其父类的构造函数。

解决方法:

由于抽象类不能被直接实例化,所以可以通过创建子类来实例化抽象类。

以下是一个示例代码:

abstract class AbstractClass {
    AbstractClass() {
        System.out.println("AbstractClass constructor called");
    }
}
class ConcreteClass extends AbstractClass {
    ConcreteClass() {
        super();
        System.out.println("ConcreteClass constructor called");
    }
}
public class Main {
    public static void main(String[] args) {
        ConcreteClass obj = new ConcreteClass();
    }
}

代码执行结果:

AbstractClass constructor called

ConcreteClass constructor called

从以上代码可以看出,在创建ConcreteClass对象的过程中,JVM调用了抽象类AbstractClass的构造函数。这是因为抽象类不能被直接实例化,但它的构造函数可以被子类调用。

因此,为了实例化一个抽象类,我们需要创建一个子类并调用其构造函数。通过调用子类的构造函数,父类的构造函数也会被自动调用。

这样,我们就可以间接地实例化抽象类,并且通过在子类中添加自定义的实现,实现对抽象类的扩展和使用。

0
0 Comments

JVM内部是否为抽象类实例化一个对象?

不,但这是一个常见的误解(这也是一个合理的方式,像JavaScript这样的原型语言就是这样做的)。

JVM创建了一个对象,它的类是你创建的类(在这种情况下是ConcreteClass)。这个对象有它的超类(MyAbstractClass)和它的子类(ConcreteClass)的一些方面,但只有一个对象。

这个对象是所有部分的集合,包括看起来具有相同名称的部分,比如被子类覆盖的超类的方法。实际上,这些方法具有不同的完全限定名称,彼此不冲突,这就是为什么可以调用超类版本的重写方法的原因。

那么如果只有一个对象,为什么您会看到对MyAbstractClass构造函数的调用?在回答这个问题之前,我需要提到一些Java编译器在源代码中看不到的事情:

1. 它为ConcreteClass创建了一个默认构造函数。

2. 在构造函数中,它调用了MyAbstractClass的构造函数。

3. 为了保险起见:在MyAbstractClass的构造函数中,它添加了对超类(Object)构造函数的调用,因为在MyAbstractClass的构造函数中没有写入super(...)调用。

以下是在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();
    }
}

好了,现在让我们谈谈TheLostMind在评论中提到的一个有用的观点:“构造函数不会创建对象,它们只是初始化对象”。JVM创建对象,然后对该对象运行尽可能多的构造函数(实际上应该称为初始化器),以使每个超类有机会初始化它的那部分对象。

所以在上面的代码中,发生了以下情况(您可以在调试器中逐步进行,以完全理解):

1. JVM创建一个对象。

2. 调用ConcreteClass的构造函数:

- 构造函数的第一件事是调用其超类的构造函数,即MyAbstractClass的构造函数。(请注意,这是一个绝对的要求:Java编译器不允许您在构造函数本身之前放置任何逻辑,而不是在调用超类构造函数之前。)

- 构造函数的第一件事是调用其超类(Object)的构造函数。

- 当Object构造函数返回时,继续运行MyAbstractClass的构造函数。

3. 当MyAbstractClass的构造函数返回时,继续运行ConcreteClass的构造函数。

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

请注意,如果存在具有初始值的实例字段,上述过程将变得更加复杂。有关完整细节,请参阅JLS和JVM规范。

那么调用构造函数的意义是什么?

确保运行初始化对象的基本部分所需的逻辑。

那么在没有对象的情况下,构造函数如何存在?(在抽象类的情况下)

MyAbstractClass的构造函数对已创建的ConcreteClass对象进行操作,只是它只能看到该对象的一部分,而不是整个对象。

构造函数和方法不是对象的一部分,它们是类的一部分。类=代码,对象=数据。代码(抽象构造函数)在数据(对象)上操作。

您正在忽略的一点是:“构造函数只初始化对象,而不是创建它们”。

JLS §12.5似乎与此相关。

在上述文档中提到:“在将新创建的对象的引用作为结果返回之前,将处理指定的构造函数,以使用以下过程初始化新对象:”。这意味着首先创建对象,然后在返回对象作为结果之前执行其构造函数。

我在列表中有些地方没详细说明,我已经更新了答案的部分。建议从头到尾重新阅读上面的答案,不要跳过您认为已经知道的部分。

因此,我们可以说构造函数不是对象的一部分。如果我在抽象类的构造函数中设置一个变量,那么我们可以认为这些变量不属于对象吗?

您是否真的指的是变量(例如,构造函数中的局部变量),还是指的字段(对象上的字段)?如果是后者,引用答案中的句子:“该对象的所有部分都来自其超类...和其子类”。抽象类定义并由其构造函数初始化的字段绝对是对象的一部分。

让我们在聊天中继续讨论。

0