1. 为什么需要构造方法
代码冗余与遗漏风险:创建对象后,如果仅使用 setter 方法逐一初始化字段,需要编写多行代码,且容易遗漏调用某些 setter,导致对象状态不完整。
构造方法的优势:构造方法允许在创建对象的瞬间完成所有必要字段的初始化,使代码更简洁,并强制提供完整初始状态,从而更安全。
示例对比:
- 使用 setter(易出错):Person ming = new Person();
ming.setName("小明");
ming.setAge(12); // 若忘记此调用,age 将保持默认值 0 - 使用构造方法(推荐):Person ming = new Person("小明", 12); // 一行代码,强制完成初始化
2. 什么是构造方法?
构造方法是一种特殊方法,用来在创建对象时初始化对象字段。
语法示例
class Person {
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
调用
public class Main {
public static void main(String[] args) {
Person p = new Person("小明", 15);
System.out.println(p.getName()); // 小明
System.out.println(p.getAge()); // 15
}
}
3. 构造方法的特点
2.没有返回值类型
普通方法可能写成
public String getName()
而构造方法不能写返回类型,例如 public Person(),不能写成 public void Person()。
3.必须通过 new 调用
构造方法不能像普通方法那样直接调用:
p.Person("小明",15);//错误
Person p = new Person("小明",15);//new调用,正确
4.可以重载
一个类可以有多个构造方法,参数列表不同。
4. 默认构造方法
如果一个类没有定义任何构造方法,编译器会自动生成一个无参构造方法。
例如:
class Person {
private String name;
private int age;
}
编译器会自动生成类似这样的构造方法:
class Person {
private String name;
private int age;
public Person() {
// 空构造方法
}
}
所以我们可以直接:
Person p = new Person();
重要规则
一旦你自己定义了任意一个构造方法,编译器就不再自动生成默认无参构造方法。
例如:
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
这时再写:
Person p = new Person(); // 编译错误!找不到无参构造方法
因为编译器不再自动提供 Person()。
如果既想要无参构造方法,又想要有参构造方法,必须手动把两个都写出来:
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
5. 字段默认值
如果构造方法没有给字段赋值,字段会使用默认值。
类型 默认值
byte / short / int / long 0
float / double 0.0
char '\\u0000'
boolean false
引用类型,例如 String null
示例:
public class Main {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p.getName());//null
System.out.println(p.getAge());//0
System.out.println(p.getVip());//false
}
}
class Person {
private String name;
private int age;
private boolean vip;
public Person() {
}
public Person(String name, int age, boolean vip) {
this.name = name;
this.age = age;
this.vip = vip;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public boolean getVip() {
return vip;
}
}
6. 字段初始化器
我们可以在声明字段时直接赋初值:
class Person {
private String name = "未命名";
private int age = 10;
}
这样即使构造方法没有给字段赋值,字段也有默认的初始值。
7. 构造方法重载
重载:在同一个类中,允许定义多个构造方法,只要它们的参数列表不同(参数个数、类型或顺序不同)。
重载的目的:提供多种创建对象的方式,让使用者可以根据实际情况灵活传参,而不必为每种情况写不同的方法名。
class Person {
private String name;
private int age;
// 构造方法①:两个参数
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 构造方法②:一个参数(String)
public Person(String name) {
this.name = name;
this.age = 18;
}
// 构造方法③:无参数
public Person() {
}
}
Person p1 = new Person("小明", 20); // 调用 Person(String, int)
/*
传入实参:"小明"(String)、20(int)
匹配到构造方法① Person(String, int)
执行:this.name = "小明",this.age = 20
结果:p1 对象的 name = "小明",age = 20
*/
Person p2 = new Person("小红"); // 调用 Person(String)
Person p3 = new Person(); // 调用 Person()
- 提供灵活性:调用者可以只给名字(年龄自动成年),也可以给名字+年龄,甚至可以完全默认(比如用于后续 setter 赋值)。
- 减少重复代码:如果没有重载,你可能需要写 setName()、setAge() 或者多个不同名的创建方法,而重载让 new 本身就完成了差异化初始化。
8. 用 this(…) 调用其他构造方法
一个构造方法可以调用另一个构造方法,语法是 this(参数…)。
作用:复用初始化逻辑,避免重复代码。
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this(name, 18); // 调用 Person(String, int)
}
public Person() {
this("未命名"); // 调用 Person(String)
}
}
注意:this(…) 必须写在构造方法的第一行。
错误写法:
public Person() {
System.out.println("初始化");
this("未命名"); // 编译错误,this(…)必须放在第一行
}
9. 字段初始化与构造方法的执行顺序
创建对象时,Java 按以下顺序初始化:
private int age = 10;
这时 name 变成 “未命名”,age 变成 10。
1.先给字段分配默认值。
例如 String name 先变成 null,int age 先变成 0。
2.执行字段初始化器。
例如:
private String name = "未命名";
private int age = 10;
这时 name 变成 “未命名”,age 变成 10。
执行构造方法体的代码。
如果构造方法体中再次给字段赋值,会覆盖前面的值。
示例
class Person {
private String name = "未命名";
private int age = 10;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
执行:
Person p = new Person("小明", 12);
过程:
name 初始为 null,age 初始为 0
字段初始化器执行:name = “未命名”,age = 10
构造方法体执行:name = “小明”,age = 12
最终结果:
java
p.getName(); // 小明
p.getAge(); // 12
所以:字段初始化器先执行,构造方法体后执行,最终值由构造方法体决定。
public class Main {
public static void main(String[] args) {
System.out.println(">>> 开始执行 new Person(\\"小明\\", 12) <<<");
Person p = new Person("小明", 12);
System.out.println(">>> new 操作执行完毕 <<<");
p.show();
}
}
class Person {
// 1. 字段定义 + 字段初始化器 (带打印)
private String name = "未命名";
private int age = 10;
// 2. 实例初始化块 (它在字段初始化器之后、构造方法体之前执行)
{
System.out.println("【步骤3】执行 实例初始化块 { } 内的代码");
System.out.println(" 此时 name = " + name + ", age = " + age);
// 假设这里偷偷改一下年龄,看看会不会被构造方法覆盖
this.age = 99;
System.out.println(" 初始化块执行完毕,age 被改为 99");
}
// 3. 构造方法体
public Person(String name, int age) {
System.out.println("【步骤4】进入 构造方法体 public Person(String name, int age)");
System.out.println(" 执行构造方法前:this.name = " + this.name + ", this.age = " + this.age);
this.name = name;
this.age = age;
System.out.println(" 执行构造方法后:this.name = " + this.name + ", this.age = " + this.age);
}
// 用来查看最终结果的普通方法
public void show() {
System.out.println("【最终对象结果】name = " + name + ", age = " + age);
}
}
网硕互联帮助中心




评论前必须登录!
注册