15.3 客户信息
把三层蓝图里的"货物"造出来——Customer 客户实体类。五个字段(姓名/性别/年龄/电话/邮箱)+ 全套 getter/setter + 两种构造器,全部是 4.3 封装和 3.4 构造方法的老手艺,本节没有新知识,只有老规矩在真项目里的第一次正式上岗。写完它,CRM 的地基就三块齐了两块。
一、Customer 是三层里的哪一层
15.1 定的分工口诀:脸管喊话,库管货,实体管数据,工具管打字。Customer 就是那个"实体管数据"——它自己不干任何业务,只负责把一个客户的所有信息装在一起。
为什么要专门造个类装数据,而不是用五个散变量?因为客户是"一个"客户:姓名、电话、邮箱是长在同一个人身上的。散变量一转身就分家,Customer 对象走到哪,这个人完整的信息就跟到哪——这就是 3.1 面向对象"把数据和行为打包"的思想第一次派上真用场。
二、核心:五个字段 + 官方通道
public class Customer {
private String name; // 姓名
private char gender; // 性别(男/女,单字符用 char 恰好)
private int age; // 年龄
private String phone; // 电话
private String email; // 邮箱
// 全参构造:new 的同时五个全给
public Customer(String name, char gender, int age, String phone, String email) {
this.name = name;
this.gender = gender;
this.age = age;
this.phone = phone;
this.email = email;
}
// 无参构造:先要空壳,回头逐项 set
public Customer() {
}
// 五对 getter / setter —— 数据只走官方通道
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// gender / age / phone / email 同款,一式五份……
// 调试利器:show() 把客户信息一行打出来
public String show() {
return name + "\t" + gender + "\t" + age + "\t" + phone + "\t" + email;
}
}
三处讲究全是老账:
- 字段全 private(3.3 封装性):外人直接
c.age = -5的野路子一律堵死,想动数据必须走setAge()——将来要在 setter 里加校验(比如年龄不能是负数),一处加锁全局生效。 - this. 区分(3.5 this):参数名和字段名撞车,
this.name = name左边是字段、右边是参数——这个老朋友现在天天见面了。 - 两种构造都留(3.4 构造方法):写了全参构造,无参构造会被顶掉,必须手动补上——因为两条造货路线都要用(见下)。
路线 A:Customer c = new Customer(); 然后 c.setName("波仔"); c.setAge(28); 逐项填空。路线 B:Customer c2 = new Customer("小明", '男', 25, "13800000000", "[email protected]"); 一步到位。两条路各 new 一个,用 show() 打出来对比——字段值一样,殊途同归。
在 CustomerTest 里写 c.name = "黑客"——编译报错,name has private access。换 c.setName("黑不了") 立刻通过。4.3 说的"封装保护数据",今天亲眼验证。
把 public Customer() {} 注释掉,再写 new Customer()——编译报错。原因:一旦手写了全参构造,编译器就不再白送无参构造。这个坑后面 Spring 等框架里会反复遇到,现在就刻进肌肉记忆。
三、show():实体类的"自我介绍"
实体类不该有业务,但打印自己不算业务——show() 返回一行格式化好的客户信息,列表页直接调用,五个字段用 \t 隔开对齐。这是给 15.5 的"客户列表"功能提前铺路:库房把每个客户的 show() 拼起来,就是一张表格。
四、Demo33:造三个客户试跑
public class Demo33 {
public static void main(String[] args) {
// 路线 B:全参一步到位
Customer c1 = new Customer("小明", '男', 25, "13800000001", "[email protected]");
// 路线 A:无参 + 逐项 set
Customer c2 = new Customer();
c2.setName("小红");
c2.setGender('女');
c2.setAge(23);
c2.setPhone("13800000002");
c2.setEmail("[email protected]");
System.out.println("姓名\t性别\t年龄\t电话\t\t邮箱");
System.out.println(c1.show());
System.out.println(c2.show());
}
}
运行看到两行整齐的客户信息,Customer 就算正式下线合格——注意 main 里没有任何数据被乱摸,全走 getter/setter 官方通道。
五、五个常见误区
图省事直接 public String name——封装形同虚设,将来没法统一加校验。实体类字段默认全 private,条件反射级别。
编译器白送的无参构造在你手写全参那一刻就没了,回头 new Customer() 直接报错。规矩:写了带参构造,必补无参。
比如在 setName() 里顺手打印"欢迎新客户"——实体类是纯货物,不干业务,业务是 View 的活。setter 将来只加校验(格式对不对),不加业务。
'男' 是单字符,char gender 恰好够用;写成 String 也不算错,但要记住传的是 "男" 带双引号。本教材用 char,跟着教材走,重点是类型和字面量要配对(char 用单引号)。
把链表思维混进来,实体类越写越复杂。Customer 只管一个客户的数据;"客户们怎么摆"是 CustomerList 库房的职责——分工口诀再念一遍。
六、自测题
name/phone/email 是 String,age 是 int,gender 是 char——性别是单字符,char 用单引号 '男' 恰好。
不好。private 堵死野路子赋值,所有数据进出都走 setter/getter,将来加校验(如年龄非负)一处生效;public 一散出去就收不回来了。
手写带参构造后编译器不再赠送无参构造。手动补一个空的无参构造即可。
造新客户两路皆可;修改功能只能用 A 的单个 set(只动一个字段);B 适合数据齐全时一步到位。
用路线 A:拿到已有对象后只调 c.setPhone("新号码"),其余字段不动——这正是"修改客户"功能(15.5)的核心一行。顺带体会:没有 setter 的话,这个需求就得拆开重建整个对象。
七、下一步学什么
- ☑ 15.4 个人信息 ✅ 已完成 —— User 类照同款封装模板再套一遍,admin 账号实体化 + 改密码 equals 校验,点此复习。
相关笔记
- 第三章 面向对象(上)/3.3 封装性:private + getter/setter 的标准姿势,本节首次项目级上岗
- 第三章 面向对象(上)/3.4 构造方法:两种构造器并存的老规矩
- 第三章 面向对象(上)/3.5 this关键字:
this.name = name天天见面的老朋友 - 第二章 Java编程基础/2.7 数组:CustomerList 库房接下来要用的货架手艺
- 第十五章 综合项目:客户关系管理系统/15.1 项目开发准备:三层蓝图的源头
- 第十五章 综合项目:客户关系管理系统/15.2 用户登录:启动链的上一环,门卫已放行