构造方法
构造方法是创建对象时调用的特殊方法,用于初始化对象的状态。
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. 构造方法不能被继承
子类不能重写父类的构造方法,因为父类的构造方法不属于子类:
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()串联构造方法,避免重复代码 - 子类构造方法会自动调用父类的无参构造
- 不要在构造方法中调用可被子类重写的方法
