Skip to content

构造方法

构造方法是创建对象时调用的特殊方法,用于初始化对象的状态。

java
public class Person {
    private String name;
    private int age;

    // 这就是构造方法:与类名相同,没有返回类型
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// 使用:new Person() 时会调用构造方法
Person p = new Person("张三", 25);

默认构造方法

如果类中没有显式定义构造方法,编译器会自动生成一个无参构造:

java
public class Person {
    private String name;
}

// 编译器自动生成相当于这个:
public class Person {
    private String name;

    public Person() {
        // 空的
    }
}

一旦定义,不再自动生成

java
public class Person {
    private String name;

    // 显式定义了有参构造
    public Person(String name) {
        this.name = name;
    }
}

// ❌ 编译错误:没有无参构造了
Person p = new Person();

// ✅ 使用有参构造
Person p = new Person("张三");

构造方法链

使用 this() 调用同类中的其他构造方法,避免代码重复:

java
public class Person {
    private String name;
    private int age;
    private String gender;
    private String address;

    // 无参构造
    public Person() {
        this("未知", 0);
    }

    // 单参构造
    public Person(String name) {
        this(name, 0);
    }

    // 双参构造
    public Person(String name, int age) {
        this(name, age, "未知");
    }

    // 三参构造
    public Person(String name, int age, String gender) {
        this(name, age, gender, "未知");
    }

    // 全参构造(真正初始化的地方)
    public Person(String name, int age, String gender, String address) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.address = address;
    }
}

调用时:

java
new Person()                   → 调用 Person("未知", 0) → ... → 全参构造
new Person("张三")             → 调用 Person("张三", 0) → ... → 全参构造
new Person("李四", 25)         → 调用 Person("李四", 25, "未知") → ... → 全参构造
new Person("王五", 30, "男")   → 调用 Person("王五", 30, "男", "未知") → 全参构造
new Person("赵六", 35, "女", "北京") → 直接调用全参构造

注意事项

this() 调用必须放在构造方法的第一行:

java
public class Example {
    public Example() {
        // ❌ 错误:this() 必须在第一行
        System.out.println("Before");
        this("value");
    }

    public Example(String value) {
        // ✅ 正确:this() 在第一行
        this();
    }
}

super 调用父类构造方法

子类构造方法会自动调用父类的无参构造:

java
class Parent {
    public Parent() {
        System.out.println("父类构造方法");
    }
}

class Child extends Parent {
    public Child() {
        // 隐式调用 super()
        System.out.println("子类构造方法");
    }
}

new Child();
// 输出:
// 父类构造方法
// 子类构造方法

显式调用

使用 super() 调用父类的有参构造:

java
class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }
}

class Child extends Parent {
    private int age;

    public Child(String name, int age) {
        super(name);  // 调用父类有参构造
        this.age = age;
    }
}

执行顺序

对象创建时,各类代码块的执行顺序:

java
class Parent {
    static {
        System.out.println("父类静态代码块");
    }

    {
        System.out.println("父类实例代码块");
    }

    public Parent() {
        System.out.println("父类构造方法");
    }
}

class Child extends Parent {
    static {
        System.out.println("子类静态代码块");
    }

    {
        System.out.println("子类实例代码块");
    }

    public Child() {
        System.out.println("子类构造方法");
    }
}

new Child();

执行顺序:

  1. 父类静态代码块
  2. 子类静态代码块
  3. 父类实例代码块
  4. 父类构造方法
  5. 子类实例代码块
  6. 子类构造方法

常见问题

1. 构造方法不能被继承

子类不能重写父类的构造方法,因为父类的构造方法不属于子类:

java
class Parent {
    public Parent() { }
}

// ❌ 错误:不能重写构造方法
// class Child extends Parent {
//     public Parent() { }
// }

2. 构造方法可以是 private

私有构造方法常用于单例模式或阻止直接实例化:

java
public class Singleton {
    private static Singleton instance;

    // 私有构造方法
    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

最佳实践

1. 保持构造方法简洁

构造方法只做最必要的初始化,可选参数用 setter 或 Builder 模式:

java
public class User {
    private String name;
    private int age;
    private String email;

    // ✅ 简洁的构造方法,只初始化必填字段
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 可选参数用 setter
    public void setEmail(String email) {
        this.email = email;
    }
}

2. 不要在构造方法中调用可被子类重写的方法

这可能导致不可预期的行为:

java
public class Parent {
    public Parent() {
        doInit();  // ❌ 危险:此时子类可能还没初始化
    }

    public void doInit() {
        System.out.println("Parent init");
    }
}

class Child extends Parent {
    @Override
    public void doInit() {
        System.out.println("Child init");  // 可能会被执行
    }
}

3. 构造方法链是好实践

this() 串联构造方法,确保初始化逻辑集中在一处:

java
// ✅ 好:所有字段在一个地方初始化
public Person(String name, int age, String gender, String address) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.address = address;
}

// ❌ 坏:重复赋值
public Person() {
    this.name = "未知";
    this.age = 0;
    this.gender = "未知";
    this.address = "未知";
}

public Person(String name) {
    this.name = name;      // 重复!
    this.age = 0;         // 重复!
    this.gender = "未知";  // 重复!
    this.address = "未知"; // 重复!
}

总结

  • 构造方法与类名相同,无返回类型
  • 如果没有定义构造方法,编译器会自动生成无参构造
  • this() 串联构造方法,避免重复代码
  • 子类构造方法会自动调用父类的无参构造
  • 不要在构造方法中调用可被子类重写的方法

基于 VitePress 构建