Java 基础 Day01:基础语法、数组与面向对象入门
2084 字
10 分钟
Java 基础 Day01:基础语法、数组与面向对象入门
基础综合练习
这一组练习围绕 Scanner 输入、Math.random() 随机数、if/else、switch、while 循环和方法拆分展开。
BMI / BMR 健康计算器
Scanner依次接收身高、体重、性别、年龄- 常量定义边界:
private static final double THIN_LIMIT = 18.5; - 三元运算符按性别选公式:
sex.equals("男") ? 男公式 : 女公式 - 链式 if-else 判断 BMI 区间(未成年单独提示)
- 格式化输出:
System.out.printf("BMI: %.2f%n", bmi)
double bmr = sex.equals("男") ? 66 + (13.7 * weight) + (5 * height) - (6.8 * age) : 655 + (9.6 * weight) + (1.8 * height) - (4.7 * age);猜数字游戏
- 随机数生成:
int number = (int)(Math.random()*100) + 1;(Math.random()返回[0,1),乘以 n 后取整得到[0, n-1]的整数,再加偏移得到目标区间,这里是[1,100]) while(true)+break实现”直到猜对才退出”的循环
简易计算器
- JDK 14+ 的 switch 表达式箭头语法:
case "1" -> System.out.println(input + input2); - 用
String c = sc.next(); if (c.equals("n")) break;控制是否继续
验证码生成
- 字符池法:把数字 + 大小写字母拼成一个字符串,每次随机取下标
StringBuffer拼接(注意:append返回自身,可链式调用)
String str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";int index = (int)(Math.random() * str.length());sb.append(str.charAt(index));素数查找
- 方法拆分:主方法只负责遍历统计,判断逻辑单独抽成
isPrime(int n)(单一职责) - 优化点:
for (int i = 2; i <= n/2; i++)只需判断到n/2,减少一半循环
数组
成绩统计
- 数组默认初始化:
double[] scores = new double[8];(默认全为0.0) Arrays.sort(scores)排序后,scores[0]是最低分,scores[len-1]是最高分- 增强 for 遍历累加求和:
for (double score : scores)
斗地主发牌(综合练习)
- 方法拆分:
initcards()初始化 54 张牌 →shuffle()洗牌 →deal()发牌 →printCards()展示 - 嵌套循环生成 52 张普通牌:下标 =
花色索引 * 13 + 牌值索引 - 取模发牌法:
i % 3 == 0/1/2分给三个玩家,i >= 51留给底牌 - 洗牌用经典的交换法:随机下标与当前下标交换
if (i >= 51) dipai[i - 51] = cards[i]; // 最后 3 张是底牌else if (i % 3 == 0) player1[i / 3] = cards[i];else if (i % 3 == 1) player2[i / 3] = cards[i];else player3[i / 3] = cards[i];数字华容道(二维数组)
- 二维数组:
int[][] arraystone = new int[n][n];,用count++顺序填充 1~16 - 打乱:双重循环内随机选一个位置与本位置交换
- 增强 for 遍历二维数组(双层):外层取行,内层取元素
面向对象入门
类与对象
- 游戏角色类:
private属性 + getter/setter 对外暴露 +show()方法展示信息 - 封装雏形:属性私有,外部通过
star.setName("追踪者")赋值
构造器
- 无参构造 / 有参构造 / 构造器重载:同名方法通过参数列表区分
- 构造器特点:方法名 = 类名、无返回值类型、
new时自动执行
public Student() { } // 无参public Student(String name, int age) { } // 有参public Student(String name) { } // 重载封装
private修饰敏感数据(chinese/math),对外只暴露 getter/setter- 业务方法放类内部:
printallscore()/printavgscore()直接访问私有字段计算 - 注意:
name是默认访问权限(同包可见),这是与private的对比
this 关键字
- 哪个对象调用方法,
this就指向哪个对象 - 常用于:成员变量名与参数名相同时区分(
this.name = name)
静态字段
- 静态成员(static)属于类,整个程序只加载一份,所有对象共享
- 实例成员属于对象,每个对象各有一份
- 演示:
s1.name、s2.name指向同一份静态数据,改一个全变
| 成员类型 | 归属 | 内存 | 访问方式 |
|---|---|---|---|
| 静态(static) | 类 | 只加载一份,共享 | 类名.成员 推荐 |
| 实例 | 对象 | 每对象一份 | 对象.成员 |
静态方法与工具类设计
- 静态方法只能访问静态成员(不能直接用
this/实例变量);实例方法可以访问静态成员 - 判断口诀:方法只需做功能、不需要访问对象数据 → 设计成静态方法;必须依赖对象数据 → 实例方法
- 工具类设计套路(以验证码工具为例):
public class VerifyCodeUtil { private VerifyCodeUtil() { // 1. 私有构造器,禁止 new throw new RuntimeException("不能创建对象"); } public static String getYanzhengma(int n) { // 2. 全部静态方法 // ...字符池随机取 n 位 }}- 调用方式:
VerifyCodeUtil.getYanzhengma(4),登录、注册等不同界面复用同一个工具类
综合案例:数据类与操作类分离
- 数据类 + 操作类分离:
Movie只存数据(id/name/type/actor),MovieOperator负责业务(打印全部、按 id 查询) - 构造器注入数据:
new MovieOperator(movies)把电影数组传进操作类
Movie[] movies = new Movie[6];movies[0] = new Movie(1, "唐顿庄园", "动作", "罗宾·怀特");MovieOperator operator = new MovieOperator(movies);operator.printAllMovies();operator.searchMovieById();ArrayList 实战补充
练习环节处理的都是定长数组,ArrayList 的实际上手感来自一个控制台博客项目:有了 ArrayList,动态增删再也不用操心数组长度。
// 1. 创建ArrayList<Article> articles = new ArrayList<>();
// 2. 新增articles.add(article); // 自动扩容,不用管长度
// 3. 删除(按下标)articles.remove(i); // i 之后元素自动前移
// 4. 遍历for (Article a : articles) { ... } // 增强 for 同数组一样用
// 5. 搜索:contains 判断子串article.getTitle().contains(keyword); // 标题含关键词
// 6. 大小articles.size(); // 代替数组的 length和数组的区别(记忆口诀):
| 维度 | 数组 | ArrayList |
|---|---|---|
| 长度 | 固定,new 时定死 | 动态,自动扩容 |
| 长度访问 | .length(属性) | .size()(方法) |
| 取值 | arr[i] | .get(i) |
| 删除 | 无,只能靠下标覆盖 | .remove(i) 自动前移 |
| 用途 | 长度固定的场景 | 增删频繁的 CRUD |
实战教训:
- 工具类
ScannerUtil里nextInt()后要nextLine()吃掉换行,否则会跳过下一次输入(菜单循环里的经典坑) ArticleRepository用自增 id(nextId++)保证唯一,不用手动传——这就是数据库自增主键的雏形
博客项目实战复盘:控制台版后端的骨架
一个控制台版的博客后端练习把当天知识点串了起来——这套控制台版就是未来博客后端的骨架,下面的架构与设计决策,正式搭博客时会直接用上。
分层架构
| 层 | 类 | 职责 | 未来对应 |
|---|---|---|---|
| 实体 | entity/Article | 数据类:字段 + 读写方法 | 加 @Entity / Lombok @Data |
| 数据层 | repository/ArticleRepository | ArrayList 存取 + id 自增 | 换成 MyBatis / JPA |
| 业务层 | service/ArticleService | 业务动作 + 输入输出 | 加 @Service |
| 工具类 | util/ScannerUtil | 统一输入入口 | 保留(工具类思想通用) |
| 入口 | BlogApplication | 组装 + 主循环 | 换成 Controller + Vue |
关键设计决策
- id 自增由数据层统一维护(
nextId++)——调用者不用管,天然唯一。这就是数据库”自增主键”的雏形 - 封装 = private + 约定:
setId保留,但约定只有数据层能调用。真实项目(JPA/Lombok)实体 id 就是这么干的——不是”删 setter”,而是”约定谁该用它” - 返回副本保护内部集合:
findAll()返回new ArrayList<>(articles),防止外部拿到内部集合后绕过save()直接改——这是对”破坏封装”的防护 - 引用语义:集合里存的是对象引用,
update用 setter 改字段即持久化,不需要再 save;save 只给新文章用 - 返回值设计:
deleteById返回被删的文章而不是 boolean——调用方能给出”已删除《xxx》“的人情味提示 - Scanner 共享 + 只在退出时关闭:
private static final Scanner类级一份;close 收进exit(),不散落各方法
踩坑清单
| 坑 | 表现 | 正确做法 |
|---|---|---|
用 static 存 id | 所有文章 id 一样(static 共享,后写覆盖先写) | 每个对象各一份 → 实例字段 |
用 assert 检查 null | 默认不生效(要加 -ea 才开),拦不住 | 用 if (x == null) return; |
| null 分支忘了 return | 打印提示后继续 getTitle() → NPE 崩溃 | 找不到就 return 结束方法 |
Scanner.close() 散落各方法 | 关一次后 System.in 就废,后面全读不到 | 只在程序退出时关(exit) |
| update 里再调 save | 文章被重新分配 id 并 add 两次(重复出现) | 改引用即持久化,别重复 save |
收获:数据类 + 操作类分离的实战版
- service 里没有任何”数据怎么存”的代码,全是业务动作——数据细节被 Repository 挡住了
- 这套分层直觉,就是 Spring 里 Controller / Service / Mapper 分层的雏形
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!
Java 基础 Day01:基础语法、数组与面向对象入门
https://ryuki.icu/posts/java-basics-day01/相关文章智能推荐
1
Java 基础 Day02:继承、多态、接口与设计模式
Java继承、多态、抽象类、接口、枚举、final 与单例模式的学习笔记。
2
Java 基础 Day03:代码块、内部类、Lambda 与方法引用
Java代码块、内部类、Lambda、方法引用与 String、ArrayList 入门的学习笔记。
3
Java 进阶 Day01:异常体系与泛型入门
Java异常的两大分类、throw 与 throws、自定义异常的写法与选择,以及泛型的类型安全入门。
4
Java 进阶 Day04:线程进阶与网络编程入门
Java线程创建方式二三、线程安全与 synchronized/Lock、线程池七参数、UDP/TCP 网络编程与 JUnit 单元测试
5
Java 进阶 Day02:自定义泛型与集合入门
Java自定义泛型类、泛型接口、泛型方法与通配符,以及包装类和 Collection 集合的基础用法。
随机文章随机推荐





















