什么是 Java 中的构造函数以及如何使用它?

在面向对象的编程中,构造函数是一个特殊的函数,您可以调用它来创建对象。构造函数有几个独特的特性,使它们能够工作。

在 Java 中,您可以以其类命名构造函数。构造函数是一种方法,在它适用的类中定义。 Java 构造函数可以使用重载来提供替代行为。 Java 中的构造函数也可以利用继承来重用代码。

为什么你需要构造函数?

构造函数是面向对象编程的中流砥柱,Java 也不例外。这个例子展示了如何使用一个数据属性和一个方法定义一个基本的 Circle 类:

 public class Circle {
public double radius;
public double area() { return 3.14159 * radius * radius; }
}

然后,您可以创建此类的实例并与之交互:

 Circle c = new Circle();
c.radius = 2;
System.out.println(c.area()); // 12.56636

但这并不方便和健壮。封装数据以保护数据免受未经授权的访问是一种很好的面向对象实践:

 public class Circle {
private double radius;
public double area() { return 3.14159 * radius * radius; }
public void setRadius(double r) { radius = r; }
}

现在调用代码可以使用setRadius方法而不必担心其实现细节:

 Circle c = new Circle();
c.setRadius(2);

在创建对象时,构造函数提供了一种更好的向对象提供数据的方法。它们经常用于属性的初始化,例如这里的半径

简单构造函数的例子

最基本的构造函数是一个没有参数的构造函数,它什么都不做:

 public class Circle {
public Circle() {}
}

另请参阅:了解如何在 Java 中创建类

如果您不定义构造函数,Java 将提供一个行为相同的默认构造函数。

请注意以下几点:

  1. 构造函数的名称与类名称匹配。
  2. 此构造函数使用公共访问修饰符,因此任何其他代码都可以调用它。
  3. 构造函数不包含返回类型。与其他方法不同,构造函数不能返回值。

构造函数通常执行某种初始化。注意上面的代码并没有初始化radius的值。在这种情况下,语言会自动将其设置为零。此类期望用户使用setRadius() 。要使用比 0 更有用的默认值,您可以在构造函数中分配它:

 public class Circle {
public Circle() { radius = 1; }
}

用这个类创建的圆圈现在至少会有一个实际的区域!调用者仍然可以使用setRadius()来提供 1 以外的半径。 但是构造函数可以更友好:

 public class Circle {
public Circle(double r) { radius = r; }
}

现在,您可以从出生时创建具有特定半径的圆:

 Circle c = new Circle(2);
System.out.println(c.area()); // 12.56636

这是构造函数的一个非常常见的用途。您将经常使用它们将变量初始化为参数值。

构造函数重载

您可以在一个类定义中指定多个构造函数:

 public Circle() { radius = 1; }
public Circle(double r) { radius = r; }

这使调用代码可以选择如何构造对象:

 Circle c1 = new Circle(2);
Circle c2 = new Circle();
System.out.println(c1.area() + ", " + c2.area()); // 12.56636, 3.14159

使用稍微复杂一点的 Circle,您可以探索更多有趣的构造函数。此版本存储其位置:

 public class Circle {
public double x, y, radius;
public Circle() { radius = r; }
public Circle(double r) { radius = r; }
public Circle(double x, double y, double r) {
this.x = x; this.y = y; radius = r;
}

public double area() { return 3.14159 * radius * radius; }
}

您现在可以创建一个没有参数、单个半径或沿半径的 x 和 y 坐标的 Circle。这与 Java 支持的任何方法的重载类型相同。

构造函数链

基于另一个圈子创建一个圈子怎么样?这将使我们能够轻松复制圆形。观察以下块:

 public Circle(Circle c) {
this.x = cx;
this.y = cy;
this.radius = c.radius;
}

这会起作用,但它会不必要地重复一些代码。由于 Circle 类已经有一个处理各个属性的构造函数,您可以使用this关键字调用它:

 public Circle(Circle c) {
this(cx, cy, c.radius);
}

这是构造函数链接的一种形式,从另一个构造函数调用一个构造函数。它使用更少的代码并有助于集中操作而不是复制它。

调用父构造函数

另一种形式的构造函数链接发生在构造函数调用其父类的构造函数时。这可以是显式的,也可以是隐式的。要显式调用父构造函数,请使用super关键字:

 super(x, y);

想象一个 Shape 类充当 Circle 的父类:

 public class Shape {
double x, y;
public Shape(double _x, double _y) { x = _x; y = _y; }
}

它处理所有形状的通用定位,因为这是它们共享的功能。现在 Circle 类可以将位置处理委托给它的父类:

 public class Circle extends Shape {
double radius;
public Circle(double r) { super(0, 0); radius = r; }
public Circle(double x, double y, double r) {
super(x, y);
radius = r;
}
}

超类构造是Java继承的一个非常重要的方面。如果您没有在构造函数中显式调用super ,则该语言默认强制执行它。

构造器上的访问修饰符

构造函数可以在其签名中包含访问修饰符。像其他方法一样,这定义了哪些类型的调用者可以访问构造函数:

 public class Test {
private static Test uniqueInstance = new Test();
private Test() { }
public static Test getInstance() {
return uniqueInstance;
}
}

这是一个更复杂的例子,所以请注意理解它:

  • 该类不是抽象的,因此可以从中实例化。
  • 构造函数是私有的,所以只有这个类本身可以创建一个新实例。
  • 通过静态属性和方法,该类向调用者公开了它自己的一个唯一实例。

使用 Java 中的构造函数创建对象

构造函数对于面向对象编程至关重要。它们允许您创建对象,这是必不可少的!

在 Java 中,构造函数看起来像其他方法并且工作方式大致相同。您应该记住有关默认构造函数、重载和构造函数链的特殊规则。如果构造函数对您来说是新的,您可能想阅读在开始时应该学习的其他核心 Java 概念。