哈喽,各位 Java 学习者!欢迎来到《Java 学习日记》的第七篇内容~ 昨天我们入门了面向对象,认识了类与对象,也初步接触了构造方法和 this 关键字,但这两个知识点是对象初始化的核心,很多新手容易在 "如何正确创建对象、如何避免参数重名、如何复用构造逻辑" 上踩坑。今天我们就深入拆解构造方法的重载、this 关键字的全场景用法,结合实战案例,帮你掌握初始化对象的 "正确姿势"!
一、构造方法:对象的 "出生说明书"
回顾一下核心定义:构造方法是创建对象时自动调用的特殊方法,唯一作用是初始化对象的属性,它是对象 "出生" 时的第一个执行逻辑。
1. 构造方法的核心规则(必背)
先再强化一遍构造方法的 5 个核心规则,这是避免基础错误的关键:
- 方法名 = 类名 :必须完全一致(包括大小写),如
Student类的构造方法只能是Student(); - 无返回值类型 :连
void都不能写(写了就变成普通方法); - 支持重载:一个类可以有多个构造方法,只要参数列表(个数、类型、顺序)不同;
- 默认构造:如果手动定义了任何构造方法,JVM 提供的默认无参构造会失效;
- 权限修饰符 :通常用
public(允许外部创建对象),也可根据需求用private(单例模式)。
2. 构造方法的重载:适配不同初始化场景
重载是构造方法的核心特性 ------ 针对不同的初始化需求(比如只给姓名赋值、给姓名 + 年龄赋值、给所有属性赋值),提供不同参数的构造方法,让对象创建更灵活。
实战 1:构造方法重载(学生类示例)
java
运行
java
public class Student {
// 私有属性
private String name;
private int age;
private String gender;
private double score;
// 1. 无参构造(手动定义,避免默认构造失效)
// 场景:创建空对象,后续通过setter赋值
public Student() {
System.out.println("无参构造被调用:创建空学生对象");
// 可在无参构造中设置默认值
this.gender = "未知";
this.score = 60.0;
}
// 2. 单参构造(仅初始化姓名)
// 场景:只知道姓名,其他属性用默认值
public Student(String name) {
this.name = name; // this区分属性和参数
this.gender = "未知";
this.score = 60.0;
System.out.println("单参构造被调用:初始化姓名=" + name);
}
// 3. 双参构造(初始化姓名+年龄)
// 场景:知道姓名和年龄,其他属性默认
public Student(String name, int age) {
this.name = name;
this.age = age;
this.gender = "未知";
this.score = 60.0;
System.out.println("双参构造被调用:初始化姓名=" + name + ",年龄=" + age);
}
// 4. 全参构造(初始化所有属性)
// 场景:知道所有属性值,一次性初始化
public Student(String name, int age, String gender, double score) {
this.name = name;
this.age = age;
this.gender = gender;
this.score = score;
System.out.println("全参构造被调用:初始化所有属性");
}
// getter/setter(简化版,仅保留核心)
public String getName() { return name; }
public int getAge() { return age; }
public String getGender() { return gender; }
public double getScore() { return score; }
}
实战 2:调用不同构造方法创建对象
java
运行
java
public class ConstructorOverloadDemo {
public static void main(String[] args) {
// 1. 调用无参构造
Student stu1 = new Student();
System.out.println("stu1:" + stu1.getName() + "," + stu1.getAge() + "," + stu1.getGender());
// 输出:stu1:null,0,未知
// 2. 调用单参构造
Student stu2 = new Student("张三");
System.out.println("stu2:" + stu2.getName() + "," + stu2.getAge());
// 输出:stu2:张三,0
// 3. 调用双参构造
Student stu3 = new Student("李四", 18);
System.out.println("stu3:" + stu3.getName() + "," + stu3.getAge());
// 输出:stu3:李四,18
// 4. 调用全参构造
Student stu4 = new Student("王五", 19, "男", 90.5);
System.out.println("stu4:" + stu4.getName() + "," + stu4.getScore());
// 输出:stu4:王五,90.5
}
}
3. 构造方法的常见坑点
坑点 1:给构造方法加返回值(变成普通方法)
java
运行
java
// 错误示例:加了void,不再是构造方法!
public void Student() {
System.out.println("这是普通方法,不是构造方法");
}
// 测试:创建对象时不会调用这个方法
public class ErrorDemo1 {
public static void main(String[] args) {
Student stu = new Student(); // 调用的是JVM默认构造(如果没手动定义)
// 需手动调用:stu.Student();
}
}
坑点 2:手动定义有参构造后,无参构造失效
java
运行
java
public class Student {
// 只定义了有参构造,默认无参构造失效
public Student(String name) {
this.name = name;
}
private String name;
}
public class ErrorDemo2 {
public static void main(String[] args) {
// 编译报错:找不到无参构造方法
// Student stu = new Student();
// 正确:只能调用有参构造
Student stu = new Student("张三");
}
}
解决方案 :手动补充无参构造(如实战 1 中的public Student() {})。
二、this 关键字:对象的 "自我指代"
this 关键字是 Java 中最常用的关键字之一,它的核心是指代当前对象------ 在类的方法 / 构造方法中,this 代表 "正在调用该方法的那个对象"。
1. this 关键字的 4 大核心用法
用法 1:区分属性与参数(最常用)
当方法 / 构造方法的参数名与类的属性名相同时,用this.属性名指代对象的属性,避免命名冲突。
java
运行
java
public class ThisDemo1 {
private String name;
private int age;
// 构造方法:参数名与属性名相同
public ThisDemo1(String name, int age) {
this.name = name; // this.name:对象的name属性;name:构造方法参数
this.age = age; // this.age:对象的age属性;age:构造方法参数
}
// 普通方法:同理
public void setInfo(String name, int age) {
this.name = name;
this.age = age;
}
public void showInfo() {
System.out.println("姓名:" + this.name + ",年龄:" + this.age);
}
public static void main(String[] args) {
ThisDemo1 obj = new ThisDemo1("张三", 18);
obj.showInfo(); // 姓名:张三,年龄:18
obj.setInfo("李四", 19);
obj.showInfo(); // 姓名:李四,年龄:19
}
}
用法 2:调用当前对象的普通方法
在类的方法中,用this.方法名()调用当前对象的其他方法(可省略 this,但建议加上,提升可读性)。
java
运行
java
public class ThisDemo2 {
private String name;
public void setName(String name) {
// 校验姓名合法性(封装到单独方法)
this.checkName(name); // 调用当前对象的checkName方法
this.name = name;
}
// 姓名校验方法
private void checkName(String name) {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("姓名不能为空!");
}
}
public static void main(String[] args) {
ThisDemo2 obj = new ThisDemo2();
// obj.setName(""); // 抛出异常:姓名不能为空!
obj.setName("张三"); // 正常执行
}
}
用法 3:调用当前类的其他构造方法(构造方法复用)
在构造方法中,用this(参数)调用同一类的其他构造方法,必须放在构造方法的第一行,核心作用是复用初始化逻辑,减少代码冗余。
java
运行
java
public class ThisDemo3 {
private String name;
private int age;
private String gender;
// 无参构造
public ThisDemo3() {
this("未知", 0); // 调用双参构造,复用逻辑
System.out.println("无参构造执行");
}
// 双参构造
public ThisDemo3(String name, int age) {
this(name, age, "未知"); // 调用全参构造,复用逻辑
System.out.println("双参构造执行");
}
// 全参构造(核心初始化逻辑)
public ThisDemo3(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
System.out.println("全参构造执行");
}
public static void main(String[] args) {
// 调用无参构造,会依次执行:全参→双参→无参
ThisDemo3 obj = new ThisDemo3();
// 输出顺序:
// 全参构造执行
// 双参构造执行
// 无参构造执行
}
}
用法 4:指代当前对象本身
在方法中,this可以直接代表当前对象(比如作为参数传递、返回当前对象)。
java
运行
java
public class ThisDemo4 {
private String name;
public ThisDemo4 setName(String name) {
this.name = name;
return this; // 返回当前对象,支持链式调用
}
public void showInfo() {
System.out.println("姓名:" + this.name);
}
// 静态方法中不能使用this(静态方法属于类,不属于对象)
public static void staticMethod() {
// System.out.println(this.name); // 编译报错:Cannot use 'this' in static context
}
public static void main(String[] args) {
// 链式调用:setName返回this,可继续调用showInfo
new ThisDemo4().setName("张三").showInfo(); // 姓名:张三
}
}
2. this 关键字的核心禁忌
- 静态方法中不能用 this:静态方法属于 "类",在类加载时就存在,而 this 指代 "对象",对象还没创建时静态方法就已存在,因此无法使用;
- this (参数) 必须在构造方法第一行:否则编译报错(JVM 要求构造方法的第一行必须是初始化逻辑);
- 不能循环调用构造方法:比如构造方法 A 调用构造方法 B,B 又调用 A,会编译报错。
三、进阶实战:构造方法 + this 实现 "链式初始化"
结合构造方法重载和 this 的链式返回特性,实现 "优雅的对象初始化",这是企业开发中常见的写法。
java
运行
java
// 商品类:支持链式初始化
public class Product {
private String id;
private String name;
private double price;
private int stock;
// 无参构造
public Product() {}
// 全参构造
public Product(String id, String name, double price, int stock) {
this.id = id;
this.name = name;
this.price = price;
this.stock = stock;
}
// setter方法返回this,支持链式调用
public Product setId(String id) {
if (id == null || id.trim().isEmpty()) {
throw new IllegalArgumentException("商品ID不能为空");
}
this.id = id;
return this;
}
public Product setName(String name) {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("商品名称不能为空");
}
this.name = name;
return this;
}
public Product setPrice(double price) {
if (price <= 0) {
throw new IllegalArgumentException("商品价格必须大于0");
}
this.price = price;
return this;
}
public Product setStock(int stock) {
if (stock < 0) {
throw new IllegalArgumentException("商品库存不能为负数");
}
this.stock = stock;
return this;
}
// 展示商品信息
public void showInfo() {
System.out.println("商品信息:ID=" + id + ",名称=" + name + ",价格=" + price + ",库存=" + stock);
}
}
// 测试链式初始化
public class ChainInitDemo {
public static void main(String[] args) {
// 方式1:构造方法+链式setter
Product p1 = new Product()
.setId("P001")
.setName("Java核心技术")
.setPrice(79.9)
.setStock(50);
p1.showInfo(); // 商品信息:ID=P001,名称=Java核心技术,价格=79.9,库存=50
// 方式2:全参构造
Product p2 = new Product("P002", "Spring实战", 89.9, 30);
p2.showInfo(); // 商品信息:ID=P002,名称=Spring实战,价格=89.9,库存=30
}
}
四、综合实战:员工类的完整初始化(构造 + this + 封装)
实现一个规范的员工类,包含完整的构造方法重载、this 用法、数据校验,覆盖企业开发中对象初始化的核心场景:
java
运行
java
public class Employee {
// 私有属性
private String empId; // 员工ID
private String empName; // 员工姓名
private int age; // 年龄
private double salary; // 薪资
private String department; // 部门
// 1. 无参构造
public Employee() {
this("未知", "未知部门"); // 调用双参构造
}
// 2. 双参构造(ID+部门)
public Employee(String empId, String department) {
this(empId, "未知", 18, 3000.0, department); // 调用全参构造
}
// 3. 全参构造(核心初始化)
public Employee(String empId, String empName, int age, double salary, String department) {
// 调用setter方法,复用校验逻辑
this.setEmpId(empId);
this.setEmpName(empName);
this.setAge(age);
this.setSalary(salary);
this.setDepartment(department);
}
// getter/setter(含校验+this)
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
if (empId == null || !empId.startsWith("EMP")) {
throw new IllegalArgumentException("员工ID必须以EMP开头!");
}
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
if (empName == null || empName.trim().isEmpty()) {
throw new IllegalArgumentException("员工姓名不能为空!");
}
this.empName = empName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 18 || age > 60) {
throw new IllegalArgumentException("员工年龄必须在18-60之间!");
}
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
if (salary < 3000) {
throw new IllegalArgumentException("员工薪资不能低于3000!");
}
this.salary = salary;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
if (department == null || department.trim().isEmpty()) {
throw new IllegalArgumentException("部门名称不能为空!");
}
this.department = department;
}
// 展示员工信息(使用this)
public void showEmpInfo() {
System.out.println("===== 员工信息 =====");
System.out.println("ID:" + this.empId);
System.out.println("姓名:" + this.empName);
System.out.println("年龄:" + this.age);
System.out.println("薪资:" + this.salary);
System.out.println("部门:" + this.department);
}
// 测试方法
public static void main(String[] args) {
// 1. 无参构造创建对象,后续setter赋值
Employee emp1 = new Employee();
emp1.setEmpId("EMP001");
emp1.setEmpName("张三");
emp1.setAge(25);
emp1.setSalary(8000.0);
emp1.showEmpInfo();
// 2. 全参构造创建对象
Employee emp2 = new Employee("EMP002", "李四", 30, 10000.0, "研发部");
emp2.showEmpInfo();
// 3. 非法数据测试(触发校验)
// Employee emp3 = new Employee("003", "王五", 17, 2000.0, "测试部");
// 抛出异常:员工ID必须以EMP开头!
}
}
五、高频避坑指南(新手必背)
- 构造方法重载时参数列表重复 :两个构造方法参数列表完全相同(如
Student(String)和Student(String)),编译报错; - this (参数) 位置错误:放在构造方法第二行及以后,编译报错;
- 静态方法中使用 this:编译报错,记住 "静态属类,非静态属对象";
- 构造方法中未复用校验逻辑:全参构造直接赋值,未调用 setter,导致数据校验失效;
- 链式调用时忘记 return this:setter 方法未返回 this,无法链式调用;
- 参数名与属性名不一致却用 this :如
this.name = username(属性是 name,参数是 username),属于多余操作(可直接name = username)。
总结
今天我们深入掌握了对象初始化的核心:构造方法的重载适配不同初始化场景,this 关键字解决了参数重名、构造方法复用、链式调用等问题。核心要点:
- 构造方法是对象初始化的入口,重载让创建对象更灵活;
- this 是对象的 "自我指代",核心用于区分属性与参数、复用构造逻辑;
- 封装 + 构造 + this 的组合,能保证对象初始化的数据安全和代码简洁。
下一篇【Day8】,我们会讲解 "继承:复用父类代码,实现代码扩展",这是面向对象三大特性的第二个核心,帮你理解如何减少代码冗余、实现类的扩展。如果今天的内容对你有帮助,欢迎点赞 + 收藏 + 关注,有任何问题都可以在评论区留言,咱们一起讨论~ 明天见!🚀