适合人群:Java初学者、正在学习面向对象和ArrayList的同学 涉及知识点:封装、构造器、ArrayList增删查、Scanner交互、String校验、Random随机卡号 阅读时长:约15分钟 系列文章:本文为ATM系统上篇,下篇将讲解存款、取款、转账等核心业务功能
目录
- 一、案例需求
- 二、系统设计分析
- 三、Account实体类
- 四、ATM主界面与开户功能
- 五、用户登录功能
- 六、运行结果演示
- 七、知识点总结
- 八、下篇预告
一、案例需求
开发一个控制台版ATM系统,实现用户的开户、登录以及后续的存取款、转账、改密、注销等完整银行业务功能。
本文(上篇)聚焦于系统框架搭建 + 开户 + 登录三大基础功能。
功能拆解
| 系统主界面 | 登录 / 开户 二选一菜单 | ✅ |
| 用户开户 | 录入姓名、性别、密码、额度,自动生成卡号 | ✅ |
| 卡号生成 | 随机8位数字,自动查重 | ✅ |
| 用户登录 | 卡号校验 + 密码校验 | ✅ |
| 存款 / 取款 | 核心业务操作 | ⏳ 下篇 |
| 转账 | 跨账户资金转移 + 姓氏验证 | ⏳ 下篇 |
| 密码修改 | 原密码验证 + 两次确认 | ⏳ 下篇 |
| 注销账户 | 余额校验 + 确认注销 | ⏳ 下篇 |
二、系统设计分析
2.1 类设计
本系统采用三层类结构,职责分离:
| Account | 实体类 | 封装账户属性:卡号、姓名、性别、密码、余额、额度 |
| ATM | 业务类 | 管理所有账户(ArrayList),实现全部业务逻辑 |
| Test | 测试类 | 创建ATM对象,启动系统 |
2.2 核心设计要点
2.3 系统流程图
程序启动
│
▼
┌──────────────┐
│ ATM主界面 │
│ 1.用户登录 │
│ 2.用户开户 │
└──────┬───────┘
│
┌───┴───┐
▼ ▼
┌──────┐ ┌──────────┐
│ 登录 │ │ 开户 │
│ │ │ 录入信息 │
│ │ │ 生成卡号 │
│ │ │ 添加到集合 │
└──┬───┘ └──────────┘
│
│ 登录成功
▼
┌──────────────────┐
│ showAtmCommand() │ ──→ 下篇详解
│ 业务操作菜单 │
└──────────────────┘
三、Account实体类
3.1 类结构
Account
├── 属性
│ ├── cardId (String) 卡号
│ ├── userName (String) 用户名
│ ├── sex (char) 性别
│ ├── passWord (String) 密码
│ ├── money (double) 余额
│ └── limit (double) 取款额度
├── 构造器
│ ├── 无参构造器
│ └── 全参构造器
└── getter/setter
└── getUserName() → 自动拼接"先生"/"女士"
3.2 代码实现
package org.atm;
public class Account {
private String cardId;
private String userName;
private char sex;
private String passWord;
private double money;
private double limit;
public Account() {
}
public Account(double limit, Double money, String passWord, char sex, String userName, String cardId) {
this.limit = limit;
this.money = money;
this.passWord = passWord;
this.sex = sex;
this.userName = userName;
this.cardId = cardId;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
// 重点:根据性别自动拼接"先生"或"女士"
public String getUserName() {
return userName + (sex == '男' ? "先生" : "女士");
}
public void setUserName(String userName) {
this.userName = userName;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public double getLimit() {
return limit;
}
public void setLimit(double limit) {
this.limit = limit;
}
}
3.3 设计亮点:getUserName() 的巧妙封装
public String getUserName() {
return userName + (sex == '男' ? "先生" : "女士");
}
小贴士:这里没有直接返回原始 userName,而是在getter中根据 sex 字段动态拼接称呼。这样调用方每次获取用户名都能自动得到"张三先生"、"李四女士"的效果,将业务逻辑封装在实体类内部,避免在每个调用处重复写判断。
四、ATM主界面与开户功能
4.1 ATM类成员定义
package org.atm;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
public class ATM {
// 所有账户集合
private ArrayList<Account> accounts = new ArrayList<>();
// 键盘录入
private Scanner sc = new Scanner(System.in);
// 当前登录的账户
private Account loginAccount;
设计要点:
- accounts 用ArrayList而非数组,因为账户数量不固定,需要动态增删
- loginAccount 是关键状态字段,登录后所有操作都围绕它进行
- Scanner 作为成员变量而非局部变量,避免反复创建
4.2 start() —— 系统主界面
public void start() {
while (true) {
System.out.println("===欢迎登录ATM系统===");
System.out.println("1. 用户登录");
System.out.println("2. 用户开户");
System.out.println("请选择:");
String choice = sc.next();
switch (choice) {
case "1":
// 用户登录
login();
break;
case "2":
// 用户开户
createAccount();
break;
default:
System.out.println("输入错误,请重新输入!");
}
}
}
小贴士:主界面用 while(true) 循环,用户操作完毕后自动返回菜单。choice 用 String 类型接收,配合 switch 匹配字符串,避免输入非数字导致程序崩溃。
4.3 createAccount() —— 用户开户
/** 开户 */
private void createAccount() {
System.out.println("====用户开户操作===");
Account account = new Account();
System.out.println("请您输入账号名称:");
String name = sc.next();
account.setUserName(name);
while (true) {
System.out.println("请您输入您的性别:");
char sex = sc.next().charAt(0);
if (sex == '男' || sex == '女') {
account.setSex(sex);
break;
} else {
System.out.println("您的输入有误,请重新输入!");
}
}
while (true) {
System.out.println("请您输入账号密码:");
String password = sc.next();
System.out.println("请您再次确认账号密码:");
String okpassword = sc.next();
if (okpassword.equals(password)) {
account.setPassWord(password);
break;
} else {
System.out.println("您输入的2次密码不正确,请重新输入!");
}
}
while (true) {
System.out.println("请设置账号额度:");
double limit = sc.nextDouble();
if (limit < 0) {
System.out.println("设置额度不合理,请重新输入!");
} else {
account.setLimit(limit);
break;
}
}
String newCardId = createCardId();
account.setCardId(newCardId);
accounts.add(account);
System.out.println("恭喜" + account.getUserName() + ",开户成功,卡号是:" + account.getCardId());
}
开户流程拆解
开户开始
│
├─① 输入姓名 ──→ setUserName()
│
├─② 输入性别 ──→ 校验"男"/"女" ──→ setSex()
│ └─ 校验失败? 重新输入
│
├─③ 输入密码 ──→ 再次确认 ──→ 比对一致? ──→ setPassWord()
│ └─ 不一致? 重新输入
│
├─④ 设置额度 ──→ 校验≥0 ──→ setLimit()
│ └─ 不合理? 重新输入
│
├─⑤ 生成卡号 ──→ createCardId() ──→ 自动查重
│
└─⑥ 加入集合 ──→ accounts.add(account)
└─ 输出开户成功信息
设计要点:每个输入项都用 while(true) 循环 + 校验,确保用户输入合法后才继续。这是控制台程序的常见交互模式。
4.4 createCardId() —— 随机生成卡号
/** 创建一个新卡号 */
private String createCardId() {
String cardId = "";
Random r = new Random();
while (true) {
for (int i = 0; i < 8; i++) {
cardId += r.nextInt(10);
}
// 判断是否与已有其他卡号重复
if (hasCardId(cardId) == null) {
break;
}
}
return cardId;
}
小贴士:生成8位随机卡号后,调用 hasCardId() 检查是否与已有卡号冲突。如果重复,while(true) 会重新生成,直到获得唯一卡号。
4.5 hasCardId() —— 卡号查重
/** 判断是否已存在卡号 */
private Account hasCardId(String s) {
for (int i = 0; i < accounts.size(); i++) {
Account acc = accounts.get(i);
if (acc.getCardId().equals(s)) {
return acc;
}
}
return null;
}
复用设计:这个方法返回 Account 对象而非 boolean。找到则返回账户对象(登录时复用),找不到返回 null。一个方法两种用途,是实际开发中常见的设计复用技巧。
五、用户登录功能
5.1 login() —— 登录逻辑
/** 登录账号 */
private void login() {
System.out.println("===用户登录操作===");
if (accounts.size() == 0) {
System.out.println("当前无任何账户,请先开户再登录!");
return;
}
while (true) {
System.out.println("请输入您的账号:");
String id = sc.next();
Account acc = hasCardId(id);
if (acc != null) {
while (true) {
System.out.println("请您输入账户密码:");
String password = sc.next();
if (acc.getPassWord().equals(password)) {
loginAccount = acc;
System.out.println(acc.getUserName() + ",欢迎您进入ATM系统");
showAtmCommand();
return;
} else {
System.out.println("账号密码输入错误,请重新输入!");
}
}
} else {
System.out.println("账号输入错误!请重新输入");
}
}
}
5.2 登录流程详解
登录采用双层 while 循环,外层校验卡号,内层校验密码:
登录开始
│
├─ 前置检查:accounts为空? → 提示先开户, return
│
└─ 外层循环(校验卡号)
│
├─ 输入卡号
│
├─ hasCardId() 查找
│ │
│ ├─ 找到 → 进入内层循环(校验密码)
│ │ │
│ │ ├─ 输入密码
│ │ │
│ │ ├─ 密码正确?
│ │ │ ├─ 是 → loginAccount = acc
│ │ │ │ 输出欢迎信息
│ │ │ │ 调用 showAtmCommand()
│ │ │ │ return ← 本文到此结束
│ │ │ │
│ │ │ └─ 否 → 提示错误, 重新输入密码
│ │ │
│ └─ 未找到 → 提示账号错误, 重新输入卡号
关键点:
5.3 showAtmCommand() —— 业务菜单入口
loginAccount = acc;
System.out.println(acc.getUserName() + ",欢迎您进入ATM系统");
showAtmCommand();
return;
登录成功后,将账户对象保存到 loginAccount,然后调用 showAtmCommand() 进入业务操作菜单。
showAtmCommand() 内部的存款、取款、转账等完整业务逻辑,将在下篇中详细讲解。
六、运行结果演示
6.1 测试类
package org.atm;
public class Test {
public static void main(String[] args) {
// 1. 创建ATM对象
ATM atm = new ATM();
// 2. 启动程序
atm.start();
}
}
6.2 运行结果 —— 开户流程
===欢迎登录ATM系统===
1. 用户登录
2. 用户开户
请选择:
2
====用户开户操作===
请您输入账号名称:
张三
请您输入您的性别:
男
请您输入账号密码:
123456
请您再次确认账号密码:
123456
请设置账号额度:
5000
恭喜张三先生,开户成功,卡号是:38472619
===欢迎登录ATM系统===
1. 用户登录
2. 用户开户
请选择:
2
====用户开户操作===
请您输入账号名称:
李四
请您输入您的性别:
女
请您输入账号密码:
888888
请您再次确认账号密码:
888888
请设置账号额度:
10000
恭喜李四女士,开户成功,卡号是:59103847
6.3 运行结果 —— 登录流程
===欢迎登录ATM系统===
1. 用户登录
2. 用户开户
请选择:
1
===用户登录操作===
请输入您的账号:
38472619
请您输入账户密码:
123456
张三先生,欢迎您进入ATM系统
6.4 运行结果 —— 异常场景
# 场景1: 无账户时尝试登录
===用户登录操作===
当前无任何账户,请先开户再登录!
# 场景2: 卡号输入错误
请输入您的账号:
99999999
账号输入错误!请重新输入
# 场景3: 密码输入错误
请输入您的账号:
38472619
请您输入账户密码:
wrong
账号密码输入错误,请重新输入!
七、知识点总结
7.1 核心知识点对照表
| 封装 | Account类私有属性 + getter/setter | getUserName()中嵌入业务逻辑 |
| ArrayList | 存储所有账户对象 | add()添加、get()遍历、remove()删除 |
| Scanner交互 | 全部用户输入 | next()接收字符串、nextDouble()接收小数 |
| while(true)循环 | 输入校验 | 校验通过break,失败继续循环 |
| 方法复用 | hasCardId()同时用于开户查重和登录查找 | 返回Account对象,一法两用 |
| Random | 生成随机8位卡号 | nextInt(10)生成0-9随机数字 |
| String比较 | 密码校验 | equals()方法,非== |
| switch匹配String | 主菜单选择 | case “1” / case “2” |
7.2 OOP设计原则体现
| 单一职责 | Account只管数据,ATM只管业务,Test只管启动 |
| 封装 | 所有字段private,外部通过getter/setter访问 |
| 方法复用 | hasCardId()在开户和登录中复用 |
7.3 易错点提醒
⚠️ 注意事项:
八、下篇预告
本文实现了ATM系统的框架搭建 + 开户 + 登录功能。下篇将接着 showAtmCommand() 方法,详细讲解:
| 查询账户 | 展示当前登录账户的完整信息 |
| 存款 | 金额校验 + 余额累加 |
| 取款 | 余额校验 + 最小金额限制 |
| 转账 | 对方账户查找 + 姓氏验证 + 额度限制 |
| 密码修改 | 原密码验证 + 两次新密码确认 |
| 注销账户 | 余额清零检查 + 确认注销 |
下篇链接:Java面向对象实战 | ATM系统(下)
如果觉得有帮助,欢迎点赞收藏关注!有问题欢迎评论区交流~




