如何在 Java 中从一个构造函数调用另一个构造函数:将改变您代码的隐藏细节
您是否曾经编写过一个包含 5-6 个构造函数的 Java 类,并感觉自己被代码重复所淹没?或者,相反,您是否看过别人的代码,其中出现神秘的 this(name, 0, true),并想知道:“这是什么魔法?”
“How do I call one constructor from another in Java?” 这个问题是 Stack Overflow 上最热门的问题之一(数千次浏览和数百个回答)。这并非偶然。看似简单的操作——调用构造函数——却隐藏着许多影响性能、可读性甚至程序正确性的细微差别。
在本文中,我们不仅会展示语法。我们将深入 JVM 内部,分析编译器如何处理此类调用,并提供对新手和经验丰富的开发人员都有用的实用建议。
为什么需要从一个构造函数调用另一个构造函数?重复问题
假设您正在编写一个 User 类,它既有必填字段(姓名、电子邮件),也有可选字段(年龄、电话)。您希望为 API 的用户提供灵活性:使用最少的数据集或所有详细信息创建对象。
糟糕的方法(不调用构造函数):
public class User { private String name; private String email; private int age; private String phone;
public User(String name, String email) { this.name = name; this.email = email; this.age = 0; // 默认值 this.phone = null; // 默认值 }
public User(String name, String email, int age) { this.name = name; this.email = email; this.age = age; this.phone = null; // 再次重复 }
public User(String name, String email, int age, String phone) { this.name = name; this.email = email; this.age = age; this.phone = phone; }}这里我们三次赋值了 name 和 email。添加新字段时,必须修改所有构造函数。这违反了 DRY(Don't Repeat Yourself)原则,并增加了出错的风险。
好的方法(通过 this() 调用构造函数):
public class User { private String name; private String email; private int age; private String phone;
public User(String name, String email) { this(name, email, 0, null); // 委托给最“完整”的构造函数 }
public User(String name, String email, int age) { this(name, email, age, null); // 再次委托 }
public User(String name, String email, int age, String phone) { this.name = name; this.email = email; this.age = age; this.phone = phone; }}现在所有初始化逻辑都在一个构造函数中。其他构造函数只是将工作委托给它,传递默认值。这简洁、易于维护,并且忘记字段的可能性更小。
调用构造函数的语法:this() 和 super()
在 Java 中,有两个用于调用构造函数的关键字:
this(参数)— 调用同一类的另一个构造函数。super(参数)— 调用父类的构造函数。
最重要的规则: this() 或 super() 调用必须是构造函数中的 第一条语句。为什么?稍后会解释。
继承示例:
class Animal { private String species;
public Animal(String species) { this.species = species; System.out.println("Animal constructor: " + speci