Java学习15
总览
- 学习目标:巩固前 9 天所有 Java 核心知识点 + 独立完成控制台版学生管理系统
- 技术栈:Java 基础语法、数组、方法、面向对象、继承、多态、抽象类、接口
- 存储方式:内存数组存储(程序关闭数据丢失,无数据库)
- 核心功能:增删改查(CRUD)+ 系统菜单 + 容错处理
上午 3 小时:Day1~Day9 全模块系统复盘
一、基础语法模块(0.6h)
核心知识点详解
- 分支结构
if-else:适用于范围判断(年龄、分数区间)switch:适用于固定值匹配(菜单选项、学号)
- 循环结构
for:已知循环次数(遍历数组、1~100 求和)while:未知循环次数,先判断后执行do-while:至少执行一次(系统菜单必备)
- 控制语句
break:结束整个循环 /switchcontinue:跳过本次循环,执行下一次
- 数据类型 + 类型转换
- 基本类型:
byte/short/int/long/float/double/char/boolean - 强制转换:
(目标类型)变量(高精度→低精度)
- 基本类型:
- Random 随机数
- 生成指定范围随机数:
nextInt(最大值-最小值+1)+最小值
- 生成指定范围随机数:
必练手写代码(完整 + 注释)
1. 1~100 求和
java
运行
public class Demo01_Sum { public static void main(String[] args) { int sum = 0; // 定义求和变量,初始值0 // for循环:已知1~100,固定次数 for (int i = 1; i <= 100; i++) { sum += i; // 累加:sum = sum + i } System.out.println("1~100求和结果:" + sum); // 输出5050 } }2. 99 乘法表
java
运行
public class Demo02_MultiTable { public static void main(String[] args) { // 外层循环:控制行数 1~9 for (int i = 1; i <= 9; i++) { // 内层循环:控制每行的列数 for (int j = 1; j <= i; j++) { System.out.print(j + "*" + i + "=" + (i*j) + "\t"); } System.out.println(); // 换行 } } }这里涉及到一个关于转义字符的知识点
表格
| 符号 | 名字 | 作用 |
|---|---|---|
| \t | 制表符 | 对齐、空一段距离 |
| \n | 换行 | 换到下一行 |
| \r | 回车 | 回到行开头 |
| \b | 退格 | 删除前一个字符 |
3. 质数判断
java
法1:
public class PrimeDemo { public static void main(String[] args) { // 待判断数字 int num = 17; boolean isPrime = true; // 不用平方根,直接遍历 2 ~ num-1 for (int i = 2; i < num; i++) { if (num % i == 0) { isPrime = false; break; } } // 三元运算符 一行打印 System.out.println(num + (isPrime ? "是质数" : "不是质数")); } }法2:Scanner 键盘输入、if/else 分开打印、平方根优化、完整注释版本
// 1. 先导包 import java.util.Scanner; public class PrimeTest { public static void main(String[] args) { // 2. 创建扫描器对象 Scanner sc = new Scanner(System.in); System.out.print("请输入一个整数:"); int num = sc.nextInt(); // 标记:默认先假设是质数 boolean isPrime = true; // 质数判断:2 ~ 平方根 for (int i = 2; i <= Math.sqrt(num); i++) { // 能整除 → 不是质数 if (num % i == 0) { isPrime = false; break; // 找到因数,直接结束循环 } } // 3. 纯 if else 分开打印(你要的格式) if (isPrime) { System.out.println(num + " 是质数"); } else { System.out.println(num + " 不是质数"); } // 关闭扫描器 sc.close(); } }这里解释一下为什么只用平方根也能直接判断
核心定理(死记)
任何一个正整数 n只要存在除 1 和自己以外的因数那它一定有一个因数 ≤ n
举例子:拿 36 举例
36=6
36 所有因数对:2×183×124×96×6
你发现规律没:
- 左边因数:2,3,4,6 全都 ≤ 6(平方根)
- 右边因数:18,12,9 全都 > 6
👉大数因数,一定是小数因数的 “搭档”
关键结论
只要:从 2 ~ 平方根 之间,找不到能整除的数→ 后半段更大的数,更不可能整除→ 直接判定:是质数
反之:只要在 2~平方根 找到一个能整除→ 直接判定:不是质数
再举你的 17
17≈4.12
只需要判断:2、3、4
- 17%2≠0
- 17%3≠0
- 17%4≠0
✅ 全部不能整除直接确定:17 是质数不用再判断 5~16,纯纯浪费时间。
一句话极简总结
因数都是成对出现一半在平方根左边,一半在右边只查左边就够了,右边不用看
通俗比喻
一双鞋子,你只要找左边鞋子有没有坏左边没问题,右边一定没问题不用两只都检查。
二、数组 + 方法模块(0.6h)
核心知识点详解
- 一维数组
- 定义:
数据类型[] 数组名 = new 数据类型[长度] - 默认值:整数 0、浮点数 0.0、布尔 false、引用类型 null
- 数组越界:访问索引
≥数组长度会报错ArrayIndexOutOfBoundsException
- 定义:
- 数组常用算法
- 遍历:for/foreach 逐个访问元素
- 最值:循环比较,记录最大 / 最小值
- 反转:首尾交换元素
- 冒泡排序:相邻元素比较交换,升序 / 降序
- 方法
- 定义:
修饰符 返回值类型 方法名(参数列表){方法体} - 重载:方法名相同,参数列表不同(个数、类型、顺序)
- 定义:
- 参数传递
- 基本类型:值传递,方法内修改不影响原值
- 引用类型:地址传递,方法内修改会影响原对象 / 数组
必练代码:数组工具类(遍历、求最大值)
java
运行
/** * 数组工具类:封装通用数组方法 */ public class ArrayUtil { // 1. 遍历打印int数组 public static void printArray(int[] arr) { if (arr == null) { // 容错:数组为空 System.out.println("数组不存在!"); return; } System.out.print("["); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + (i == arr.length-1 ? "]" : ", ")); } System.out.println(); } // 2. 求int数组最大值 public static int getMax(int[] arr) { if (arr == null || arr.length == 0) { throw new RuntimeException("数组为空,无法求最大值"); } int max = arr[0]; // 假设第一个元素为最大值 for (int num : arr) { // foreach遍历 if (num > max) max = num; } return max; } // 测试方法 public static void main(String[] args) { int[] arr = {11,22,33,44,55}; printArray(arr); // 打印数组 System.out.println("最大值:" + getMax(arr)); // 输出55 } }在执行原样输出int 的时候也很难同时也有其他打印方法
换成【if /else 直白写法】
效果完全一模一样,更好理解,考试 / 手写推荐:
java
运行
System.out.print("["); for (int i = 0; i < arr.length; i++) { if (i == arr.length - 1) { // 最后一个元素 System.out.print(arr[i] + "]"); } else { // 不是最后一个,加逗号空格 System.out.print(arr[i] + ", "); } } System.out.println();再给你一种:先打印元素,单独处理逗号(另一种常用思路)
java
运行
System.out.print("["); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]); // 不是最后一位才打逗号 if (i != arr.length - 1) { System.out.print(", "); } } System.out.print("]"); System.out.println();逻辑更好理解:
- 先打数字
- 判断:不是最后一个才补
, - 循环结束,最后补上
]
三、面向对象核心三大特性(1h)
1. 封装(核心:安全 + 易用)
- 关键字:
private(私有化成员变量) - 对外提供:
getXxx()(获取)/setXxx()(设置) - 构造方法:无参、全参(创建对象时赋值)
2. 继承(核心:代码复用)
- 关键字:
extends - 子类继承父类:拥有父类非私有成员
super:访问父类构造、成员变量、成员方法- 构造执行顺序:先父类构造,后子类构造
3. 多态(核心:统一调用,不同实现)
- 前提:继承 / 实现 + 方法重写
- 向上转型:
父类 引用 = new 子类()(统一调用) - 向下转型:
子类 引用 = (子类)父类引用(调用子类独有功能) instanceof:判断对象是否属于某个类,避免转型异常
完整案例:封装 + 继承 + 多态
java
运行
// 父类:Person class Person { private String name; private int age; // 无参/全参构造 public Person() {} public Person(String name, int age) { this.name = name; this.age = age; } // 重写方法:多态核心 public void showInfo() { System.out.println("姓名:" + name + ",年龄:" + age); } // get/set public String getName() {return name;} public void setName(String name) {this.name = name;} public int getAge() {return age;} public void setAge(int age) {this.age = age;} } // 子类:Student 继承 Person class Student extends Person { private double score; public Student() {} public Student(String name, int age, double score) { super(name, age); // super调用父类构造 this.score = score; } // 方法重写 @Override public void showInfo() { System.out.println("学生:" + getName() + ",年龄:" + getAge() + ",分数:" + score); } } // 测试多态 public class Demo04_OOP { public static void main(String[] args) { // 向上转型:父类引用指向子类对象 Person p = new Student("张三", 18, 90.5); p.showInfo(); // 执行子类重写方法(多态) // 向下转型 + instanceof判断 if (p instanceof Student) { Student s = (Student) p; s.showInfo(); } } }无参构造、有参全参构造、get/set、重写方法,IDEA 全都能一键自动生成,不用手写。
Java 面向对象三大特性 表格总结(极简好背)
表格
| 特性 | 核心作用 | 实现条件 / 关键字 | 核心语法 | 前提要求 | 通俗理解 |
|---|---|---|---|---|---|
| 封装 | 保护数据、安全访问、隐藏细节 | 私有化 + 对外提供访问 | private私有属性get/set方法构造方法 | 单个类就能实现 | 把数据锁起来,只能通过规定方法操作,防止乱改 |
| 继承 | 代码复用、减少冗余、功能拓展 | extends、super | 子类extends 父类super()调用父类构造 | 至少两个类:父类 + 子类 | 子类继承父类共有内容,只写自己独有功能 |
| 多态 | 统一调用、程序灵活、易维护扩展 | 继承 + 方法重写 + 向上转型 | @Override重写父类引用 指向 子类对象 | 1. 必有继承2. 方法重写3. 向上转型 | 父类统一标准,不同子类,执行不同功能 |
补充必背口诀
- 封装:数据私有化,方法来管控
- 继承:子类续父类,代码不用累
- 多态:编译看左边,运行看右边
四、抽象类 & 接口(0.8h)
核心知识点详解
1. 抽象类(abstract class)
- 关键字:
abstract - 抽象方法:无方法体,必须由子类重写
- 特点:不能实例化,只能作为父类被继承
- 适用场景:模板设计(定义规范,子类实现细节)
2. 接口(interface)
- 关键字:
interface(定义)、implements(实现) - 支持多实现:一个类可以实现多个接口
- 默认方法:
default修饰,有方法体,子类可直接用 - 适用场景:定义行为规范(能力扩展)
3. 抽象类 vs 接口(高频背诵 5 点)
- 抽象类:
extends单继承;接口:implements多实现 - 抽象类:可以有成员变量、构造方法;接口:只能有常量
- 抽象类:可以有普通方法 / 抽象方法;接口:JDK8+ 有默认 / 静态方法
- 抽象类:表示is-a(是什么);接口:表示like-a(有什么能力)
- 抽象类:模板设计;接口:行为扩展
4. 四种权限修饰符(从小到大)
private→默认→protected→public
完整案例:抽象类 + 接口
java
运行
// 抽象类:抽象人类 abstract class AbstractPerson { private String name; // 抽象方法:无方法体 public abstract void work(); // 普通方法 public void sleep() { System.out.println("人要睡觉"); } } // 接口:学习能力 interface Study { void study(); // 抽象方法 default void play() { // 默认方法 System.out.println("学习之余可以玩耍"); } } // 子类:实现接口 + 继承抽象类 class Student extends AbstractPerson implements Study { // 必须重写抽象类的抽象方法 @Override public void work() { System.out.println("学生的工作:学习"); } // 必须重写接口的抽象方法 @Override public void study() { System.out.println("学生正在学习Java"); } } // 测试 public class Demo05_Abstract_Interface { public static void main(String[] args) { Student s = new Student(); s.work(); s.study(); s.play(); // 调用接口默认方法 s.sleep(); // 调用抽象类普通方法 } }对比分类 | 抽象类(abstract) | 接口(interface JDK8+) |
|---|---|---|
必须有抽象方法? | 不一定 | 不一定 |
构造方法 | 一定有 | 一定无 |
继承/实现方式 | 单继承 extends | 多实现 implements |
成员变量 | 普通变量、常量都可 | 只能是常量 |
方法限制 | 普通方法、抽象方法都可 | 抽象、default、static 方法都可 |
关于抽象类和接口几个常见问题
| 序号 | 核心问题 | 标准答案 | 关键补充 |
|---|---|---|---|
| 1 | 抽象类 / 接口不写抽象方法,会自动隐藏生成吗? | 不会 | 编译器不会偷偷添加任何抽象方法;你写什么,代码里就只有什么 |
| 2 | 抽象方法一定没有方法体吗? | 是,绝对没有 | abstract方法只能声明,不能写{}方法体 |
| 3 | 只有接口有 default 方法吗? | 是 | default仅接口专属;普通类、抽象类都不能定义 |
| 4 | static 方法只有接口才有吗? | 不是 | 普通类、抽象类、接口 都能写 static 方法 |
| 5 | 含有抽象方法,必须全部重写吗? | 抽象方法必须强制重写 | 子类 / 实现类,必须覆盖所有抽象方法 |
| 6 | 抽象类里普通方法需要重写吗? | 可选,不强制 | 直接继承使用,按需重写 |
| 7 | 接口 default 默认方法需要重写吗? | 可选,不强制 | 直接调用,不满意再重写 |
| 8 | static 方法能重写吗? | 不能重写 | 静态方法不存在重写概念 |
