调用构造函数是否意味着创建对象?

16
当我们创建一个扩展抽象类的子类对象时,抽象类的构造函数也会运行。但是我们知道我们不能创建抽象类的对象。那么这是否意味着即使构造函数完成运行而没有任何异常,也不能保证是否创建了对象?

谢谢你的问题。我也有类似的疑问。 - user1986144
8个回答

21
因此,即使构造函数没有发生异常,也不能保证对象已创建?简单来说,构造函数不会创建对象,它只是初始化对象的状态。创建对象的是new操作符。现在,让我们更详细地了解一下。当您使用类似这样的语句创建一个对象时:
new MyClass();

对象首先由new运算符创建。在将对新创建的对象的引用作为结果返回之前,处理指定的构造函数以初始化新对象。


现在考虑一个抽象类和它的具体子类的情况,当你像这样做时:Abstract class 和它的具体 SubClass
AbstractClass obj = new ConcreteClass();

new 运算符创建一个 ConcreteClass 对象,并调用其构造函数来初始化所创建对象的状态。在此过程中,抽象类的构造函数也会从 ConcreteClass 构造函数中调用,以初始化抽象类中对象的状态。

因此,基本上并没有创建 AbstractClass 的对象。只是调用了其构造函数来初始化对象的状态。

学到的教训:

  • 对象是通过 new 运算符创建的,而不是通过构造函数本身的调用创建的。因此,在任何构造函数被调用之前,对象已经被创建了。

  • 构造函数仅用于初始化所创建对象的状态。它本身并不创建对象。

  • 对象状态也可以包含在抽象超类中。

  • 因此,调用 Abstract class 构造函数的目的仅是完全初始化对象,而在此过程中不会创建任何对象。

参见:


谢谢您提供非常好的解释,确实帮助了我。 - user1986144
有没有一种方法可以在不使用new运算符的情况下创建一个类的对象? - minion
1
@minion 不,没有任何方法。 - Rohit Jain

3

但我们知道我们无法创建抽象类的对象

是的,但是JVM可以。

这意味着即使构造函数完成运行而没有任何异常,也不能保证是否创建了对象吗?

对象肯定在内部创建。

调用构造函数是否意味着创建对象?

并不总是。您可以使用super()this()调用构造函数,但它不会实例化对象(只会调用构造函数)。

class AClass
{
    AClass()
    {
        this(1); // will invoke constructor, but no object instatiated.
    }

    AClass(int a)
    {

    }

    public static void main(String[] args)
    {
        AClass obj = new AClass(); // one object instantiated.
    }
}

3
注意:调用构造函数并不会创建对象,是new操作符完成了这个任务。因此,你对第三引用中的论点是错误的。 - Rohit Jain

2
除非有例外情况,抽象类构造函数只能在子类的构造函数中运行(作为第一条语句)。因此,您可以确信每次运行构造函数时,都是在创建对象的过程中。
话虽如此,在创建单个对象的过程中,您可能会调用多个构造函数,例如Subclass()调用Subclass(String),后者通过super()调用AbstractClass,依此类推。

不,它正在初始化一个对象。对象已经使用“new”运算符创建了。 - Rohit Jain
@RohitJain “每种情况都确定了一个特定的构造函数(§8.8),作为类实例创建过程的一部分,需要使用指定的参数(可能没有)进行调用。” (JLS 12.5) - Jeff Bowman
@JeffBowman.. 好的,JLS将对象的初始化包含在对象创建本身中。所以,我们都没有错。抱歉。 :) - Rohit Jain

2

子类 == 基类 + 子类中添加的额外内容

因此,当您通过调用其构造函数创建子类时,也会调用基类构造函数,以确保所有基类属性都得到适当初始化。


0

我完全不同意抽象类的对象不能被创建,只有在继承的情况下 JVM 才能创建它,即使程序员可以使用匿名类的概念在任何时候和任何地方创建它。看看这段代码,并自己尝试一下:

abstract class Amit{ 
void hai()
{System.out.print("Just Wanna say Hai");}
abstract void hello();
}
class Main{
stic public void main(String[]amit)
{
Amit aa=new Amit(){
void hello(){Sstem.out.print("I actually dont say hello to everyone");
}};
aa.hello(); }}

请不要发布您的个人电子邮件。 - Androiderson

0

您只能在 具体子类构造函数的一部分中调用抽象类构造函数。这是可以的,因为抽象类被扩展成具体类,并且正在创建一个该具体类的对象


0

当您调用子类的构造函数时,流程如下:

  1. 抽象类的构造函数运行 -> 对象在此处被半初始化。
  2. 子类的构造函数完成执行 -> 对象在此处被完全初始化,因此完全创建。

请注意,在调用构造函数之前,对象已经完全创建。 - Rohit Jain
@Rohit:我指的是此时此刻对象只完成了一半/部分初始化 :) 希望这样说法正确? - NiranjanBhat
@NiranjanBhat.. 嗯。现在很好了。 - Rohit Jain

0

当你使用new调用构造函数时,会创建一个新的对象。

现在,您可能已经知道,任何子类的构造函数都会隐式或显式地直接或间接地调用父类的构造函数(然后从父类调用其自己的父类,一直到对象)。这称为构造函数链。

然而,上述并不意味着创建了多个对象。对象已经在new调用时创建,并且所有对该对象进行操作的构造函数已经被分配了一个已分配区域。因此,构造函数链不会创建新对象。一个new调用将返回一个对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接