Java默认构造函数

190

默认构造函数是什么——你能告诉我以下哪个是默认构造函数,以及它与其他构造函数的不同之处吗?

public Module() {
   this.name = "";
   this.credits = 0;
   this.hours = 0;
}

public Module(String name, int credits, int hours) {
   this.name = name;
   this.credits = credits;
   this.hours = hours;
}
13个回答

304

两者都不是。如果你定义了构造函数,那么它就不再是默认的。

默认构造函数是没有参数的构造函数,除非你定义另一个构造函数,否则将自动生成。任何未初始化的字段都将设置为它们的默认值。对于你的示例,假设类型分别为Stringintint,而且类本身是公共的,则代码如下:

public Module()
{
  super();
  this.name = null;
  this.credits = 0;
  this.hours = 0;
}

这与之前完全相同。

public Module()
{}

如果一个类不包含构造函数声明,那么将隐式地声明一个没有形式参数和无throws子句的默认构造函数。与完全没有构造函数一样。但是,如果您定义了至少一个构造函数,则不会生成默认构造函数。

参考: Java语言规范

如果一个类不包含构造函数声明,那么将隐式地声明一个没有形式参数和无throws子句的默认构造函数。

澄清

从技术上讲,默认初始化字段的并不是构造函数(无论是默认构造函数还是其他构造函数),但我将其保留在回答中,因为

  • 问题错误地描述了默认初始化,且
  • 这些构造函数是否存在对于它们的影响完全相同。

27
您的陈述“它将任何未初始化的字段初始化为其默认值”听起来有些含糊。即使我们使用显式构造函数(带参数)或提供无参构造函数,实例变量始终会初始化为默认值。我不认为这与默认构造函数有任何关系。 - Aniket Thakur
2
@OrangeDog 在规范中哪里看到了这样的声明,即用户定义的无参数空构造函数不被称为默认构造函数? - Łukasz Rzeszotarski
2
我实际上在OCA认证考试中遇到了这个问题:“默认构造函数会初始化类的成员变量吗?”,答案是否定的。 - eis
13
@AniketThakur +1 这并不仅仅是含糊不清,而是错误的;默认构造函数不会初始化任何内容。正如这里给出的参考资料所说:“默认构造函数只是无参数地调用超类构造函数”。未初始化的字段也可以通过其他机制进行初始化,这些机制在该参考资料中也有描述。对于提供很好的参考资料的OrangeDog,我也点了+1。 - Superole
2
@Gab是好人,它被称为“无参构造函数”或“无参构造器”。 - OrangeDog
显示剩余14条评论

41

如果您的类中没有定义任何构造函数,则会创建一个默认构造函数。它只是一个不带参数且什么都不做的构造函数。编辑:除了调用super()之外。

public Module(){
}

4
具体来说,如果您编写自己的构造函数,Java将不会创建默认构造函数。因此,如果您需要一个带参数和一个不带参数(类似于默认构造函数)的构造函数,则必须编写两个! - Ralph
2
还应该注意,如果超类没有无参构造函数,则子类不能有默认构造函数(因为Java不知道如何使用默认情况下存在的构造函数)。 - Donal Fellows
8
@Sergey 这似乎与http://download.oracle.com/javase/tutorial/java/javaOO/constructors.html不一致,维基百科也是如此。 - Jim
5
我会尽力进行翻译。这是需要翻译的内容:as does the Java Language Specification! 我没有意识到Java和C++在术语上有这么大的差异。 Java语言规范也是如此。我没有意识到Java和C++在术语上有这么大的差异。 - Sergei Tachenov

23

如果您在类中没有显式定义至少一个构造函数,编译器将自动生成一个默认构造函数。您已经定义了两个构造函数,因此您的类没有默认构造函数。

根据Java语言规范第三版:

8.8.9 默认构造函数

如果一个类没有构造函数的声明,则会自动提供一个不带参数的默认构造函数...


18

你好。据我所知,让我来解释默认构造函数的概念:

编译器会自动为没有构造函数的任何类提供一个无参的默认构造函数。此默认构造函数将调用超类的无参构造函数。在这种情况下,如果超类没有无参构造函数,则编译器会报错,因此必须验证它是否存在。如果您的类没有显式超类,则具有隐式超类Object,其具有一个无参构造函数。

我从Java教程中读取了此信息。


7

当没有提供显式构造函数时,Java提供一个不带参数且不执行任何特殊动作或初始化的默认构造函数。

隐式默认构造函数只会使用super()调用调用父类构造函数。构造函数参数为您提供了一种为对象的初始化提供参数的方式。

以下是一个立方体类的示例,其中包含两个构造函数(一个默认构造函数和一个带参数的构造函数)。

public class Cube1 {
    int length;
    int breadth;
    int height;
    public int getVolume() {
        return (length * breadth * height);
    }

    Cube1() {
        length = 10;
        breadth = 10;
        height = 10;
    }

    Cube1(int l, int b, int h) {
        length = l;
        breadth = b;
        height = h;
    }

    public static void main(String[] args) {
        Cube1 cubeObj1, cubeObj2;
        cubeObj1 = new Cube1();
        cubeObj2 = new Cube1(10, 20, 30);
        System.out.println("Volume of Cube1 is : " + cubeObj1.getVolume());
        System.out.println("Volume of Cube1 is : " + cubeObj2.getVolume());
    }
}

3
你不应该这样做,而是在“默认构造函数”中写入 this(10,10,10);,它将在你的第一个构造函数中调用第二个构造函数,这将使你的代码变得更加清晰、易于理解和重构。 - julian
@Israelg99 当我们使用 this(10,10,10); 时,确切的术语是什么? - sgiri
@Israelg99 不用在意,这被称为显式构造函数调用 参考:https://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html - sgiri

6
一般术语是,如果您的对象没有提供任何构造函数,则会自动放置一个无参数构造函数,称为默认构造函数。
如果您定义了与未提供构造函数相同的构造函数,则通常被称为无参数构造函数。这只是一个约定,因为有些程序员喜欢将显式定义的无参数构造函数称为默认构造函数。但是,按照命名方式,如果我们明确地定义了一个构造函数,那么它就不是默认的。
根据 docs 如果一个类不包含构造函数声明,则隐式声明一个没有形式参数和没有throws子句的默认构造函数。
例如
public class Dog
{
}

将自动进行修改(通过添加默认构造函数),如下所示

public class Dog{
    public Dog() {

    }
} 

当你创建它的对象时

 Dog myDog = new Dog();

调用了此默认构造函数。


5

默认构造函数是指在没有程序员定义构造函数的情况下,编译器自动生成的构造函数。

如果程序员没有提供构造函数,则编译器会隐式声明一个默认构造函数,该构造函数调用super(),没有throws子句和形式参数。

例如:

class Klass {
      // Default Constructor gets generated
} 

new Klass();  // Correct
-------------------------------------

class KlassParameterized {

    KlassParameterized ( String str ) {   //// Parameterized Constructor
        // do Something
    }
} 

new KlassParameterized(); //// Wrong  - you need to explicitly provide no-arg constructor. The compiler now never declares default one.


--------------------------------

class KlassCorrected {

    KlassCorrected (){    // No-arg Constructor
       /// Safe to Invoke
    }
    KlassCorrected ( String str ) {   //// Parameterized Constructor
        // do Something
    }
} 

new KlassCorrected();    /// RIGHT  -- you can instantiate

1
实际上,默认构造函数 != 无参构造函数。无参构造函数是指任何没有参数的构造函数。默认构造函数是在类中没有声明构造函数时生成的特定无参构造函数。 - Stephen C
1
我并没有说默认构造函数等同于无参构造函数,而是说它也被称为无参构造函数。同样地,你也看不到反过来的情况,即无参构造函数是默认构造函数。你的第二个陈述正是我想表达的。 - Yergalem
你说过 - "默认构造函数也被称为无参构造函数..."。这意味着默认构造函数等同于无参构造函数。如果这不是你回答的意思,那么你应该进行更正。"你的第二个陈述是我试图表达的。" - 不幸的是,你写的和我的第二句话并不意味着相同的事情。 - Stephen C
你的更新版本仍然不正确。正确的说法是声明被自动添加了。(单词“invoke”是关于当构造函数被使用时...而不是声明时。)此外,只有在没有其他任何构造函数被声明的情况下才会自动添加。(不仅仅是带参数的构造函数。)再次强调:我不知道你是否真正了解这些事情。但是你所说的话(即你写的话)是误导性的。 - Stephen C
前几行是最重要的。它们是大多数人阅读的内容。如果你误导了他们......那就是他们会记住的! - Stephen C
显示剩余2条评论

3
如果一个类没有由程序员提供的构造函数,那么Java编译器将添加一个不带参数的默认构造函数,该函数将在内部使用super()调用调用超类构造函数。这被称为默认构造函数。
在您的情况下,由于您是通过编程方式添加它们的,因此没有默认构造函数。 如果您没有添加构造函数,则编译器生成的默认构造函数将如下所示。
public Module()
{
   super();
}

注意: 在默认构造函数里,它同样会添加super()调用,以调用父类的构造函数。

添加默认构造函数的目的:

构造函数的作用是初始化实例变量,如果没有实例变量,则可以选择从类中删除构造函数。但是当你继承某个类时,调用父类的构造函数是你类的责任,以确保父类正常地初始化所有实例变量。

这就是为什么如果没有构造函数,java编译器将添加一个默认构造函数并调用父类的构造函数。


构造函数的职责是初始化内存空间,即创建对象时所需的内存。对象的初始化是由Java虚拟机负责的。 - MaxZoom
@StephenC,不是根据这篇文章 - MaxZoom
@MaxZoom - 你可能误解了这篇文章。它说:“为了防止这种情况发生,Java确保在任何代码使用内存之前,内存至少被初始化为可预测的默认值。”- 这是JVM做的。而“任何代码”包括构造函数的代码。此外,如果你想要一个可靠的来源,请阅读JLS规定的内容。 - Stephen C
@StephenC 没错,JVM会分配默认值。由于默认构造函数中没有太多的代码,因此它是唯一执行此操作的方法。我正确理解了这篇文章。由于JLS没有提供关于默认构造函数的详细说明,我希望能有一些可靠的信息来源来支持你的观点。 - MaxZoom
但问题在于,你的评论中说构造函数执行内存初始化,而JVM执行对象初始化。实际上,JVM执行内存初始化(包括堆节点和对象头的创建),而构造函数则执行对象初始化。 - Stephen C
阅读参考文献:http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5 和 http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.new ... 注意其中关于构造函数调用的内容 ... 以及 http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9 - Stephen C

2
当我们没有为一个类显式地定义构造函数时,Java会为该类创建一个默认构造函数。它本质上是一个非参数化的构造函数,即它不接受任何参数。
默认构造函数的作用是调用超类构造函数并初始化所有实例变量。如果超类构造函数不存在,则自动将实例变量初始化为零。因此,这就达到了使用构造函数的目的,即初始化对象的内部状态,以便创建实例的代码将拥有一个完全初始化、可用的对象。
一旦我们为类定义了自己的构造函数,就不再使用默认构造函数。因此,它们中的任何一个都不是真正的默认构造函数。

0

当您的类中没有定义任何构造函数时,编译器会为您定义默认构造函数,但是当您声明任何构造函数(在您的示例中,您已经定义了一个带参数的构造函数),编译器不会为您执行此操作。

由于您在类代码中定义了构造函数,因此编译器没有创建默认构造函数。在创建对象时,您正在调用不存在于类代码中的默认构造函数。然后代码会出现编译错误。


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