学习日记-day11-5.20
完成目标:
comment.java
package com.zcr.pojo;
import org.hibernate.annotations.GenericGenerator;import javax.persistence.*;
//JPA操作表中数据,可以将对应的实体类映射到一张表上@Entity(name = "t_comment")//表示当前的实体类与哪张表进行直接映射,自动将表中的字段名称与实体类中的属性名称进行一一映射
public class Comment {@Id //表示指定实体类中用于数据映射的主键@GeneratedValue(generator = "uuid")@GenericGenerator(name = "uuid", strategy = "uuid2")@Column(name = "id")private String id;@Column(name = "article_id")private Integer articleID;@Column(name = "content")private String content;@Column(name = "author")private String author;//alt+insert 快捷键生成get,set方法public Integer getArticleID() {return articleID;}public void setArticleID(Integer articleID) {this.articleID = articleID;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}@Overridepublic String toString() {return "Comment{" +"id=" + id +", articleID=" + articleID +", content='" + content + '\'' +", author='" + author + '\'' +'}';}
}
学习java课程170-200
知识点:
1.static关键字
知识点 | 核心内容 | 重点 |
static关键字 | 用于修饰成员变量和方法,使成员属于类而非对象,实现数据共享 | 静态成员与非静态成员的内存加载顺序(静态优先) |
静态成员特点 | 1. 类加载时即存在; 2. 通过类名直接调用; 3. 所有对象共享同一静态成员 | 区分类名.静态成员与对象.非静态成员的调用方式 |
应用场景 | 解决多对象共享属性问题(如班级换教室只需修改一次静态变量) | 静态方法中不可直接调用非静态成员(需先实例化对象) |
内存机制 | 静态成员存储在方法区,非静态成员存储在堆内存对象中 | 易混淆:静态成员生命周期与类相同,非静态成员与对象绑定 |
代码示例 | static String classroom = "111";; 修改时:Student.classroom = "222"; | 需注意静态变量初始化的线程安全问题 |
2.static内存说明
知识点 | 核心内容 | 重点 |
static成员的内存存储位置 | 静态成员存储在静态域中,静态域在JDK 6时位于方法区(永久代),JDK 7开始移至堆内存 | 方法区 vs. 堆内存:JDK 7后静态域迁移至堆,目的是提高内存回收效率 |
方法区的演变 | JDK 6称“永久代”,JDK 8改为“元空间”,但均为方法区的具体实现 | 永久代、元空间与方法区的关系:需明确三者是同一逻辑区域的不同实现 |
静态域迁移原因 | 堆内存回收效率高,方法区回收效率低;迁移后可及时释放静态成员占用的内存 | 为什么静态域不留在方法区?:避免内存长期占用,优化运行性能 |
静态成员共享机制 | 静态成员随类加载而加载,被该类的所有对象共享;不属于对象成员,仅属于类 | 静态成员访问方式:直接通过类名调用(如Student.classroom),无需实例化对象 |
内存模型示例(Student类) | classroom(静态)存储在堆的静态区,name(实例)存储在对象堆内存;新建对象共享静态成员 | 对象与静态区的关系:对象通过内存地址共享静态成员,但静态成员生命周期独立于对象 |
3.静态成员访问特点
知识点 | 核心内容 | 重点 |
静态方法访问非静态成员 | 静态方法中不能直接访问非静态成员,需通过new对象调用 | 先出生的静态成员无法直接访问后出生的非静态成员(类比秦始皇不知康熙存在) |
非静态方法访问静态成员 | 非静态方法中能直接访问静态成员(同类可直接调用/类名调用,不同类需类名调用) | 反编译证明即使通过对象调用静态方法,底层仍是类名调用 |
静态方法访问静态成员 | 静态方法中能直接访问静态成员(同类可直接调用,不同类需类名调用) | 同类访问时存在两种调用方式(直接调用/类名调用) |
非静态方法访问非静态成员 | 非静态方法中能直接访问非静态成员(同类直接调用,不同类需new对象调用) | 同类访问时new对象调用非必要但可行 |
通用访问规则总结 | 非静态成员始终通过new对象调用;静态成员始终推荐类名调用 | 静态成员生命周期早于非静态成员(类加载vs对象实例化) |
4.静态成员的使用场景
知识点 | 核心内容 | 重点 |
静态成员的使用场景 | 静态成员通过类名直接调用,无需实例化,适用于工具类等场景 | 静态成员与实例成员的区别(内存加载时机) |
静态成员的局限性 | 所有静态成员会在类加载时占用内存,滥用会导致内存浪费 | 需权衡“便利性”与“资源占用” |
工具类设计规范 | 1. 成员全静态化; 2. 构造方法私有化(禁止实例化); 3. 功能需高频复用(如数组求最大值) | 工具类与普通类的设计差异 |
代码复用案例 | 抽取ArrayUtils.getMax()方法,避免重复编写数组遍历逻辑 | 工具类方法的通用性设计(参数/返回值) |
5.可变参数
知识点 | 核心内容 | 注意事项 |
可变参数定义 | 使用数据类型...变量名语法定义(必须三个点) | 必须三个点,两个或四个点都不行 |
可变参数本质 | 底层实现是数组(可通过反编译验证) | 可使用数组遍历方式操作可变参数 |
参数位置规则 | 可变参数必须放在参数列表最后 | 报错提示:varargs parameter must be the last |
多参数共存 | 可与普通参数共存(如int i, int... arr) | 普通参数需在前,顺序不可颠倒 |
方法调用方式 | 可传入任意数量同类型参数(自动转为数组) | 类型必须匹配定义的数据类型 |
6.递归
知识点 | 核心内容 | 重点 |
递归的定义 | 方法内部调用自身的编程技巧 | 与循环的区别(出口条件的必要性) |
递归的经典案例 | "从前有座山"的无限循环故事 | 无出口的递归导致栈溢出错误 |
递归的分类 | 直接递归(方法A调A)和间接递归(方法A→B→C→A循环调用) | 间接递归的代码实现逻辑 |
递归的注意事项 | 必须设置终止条件(出口),且递归次数不宜过多 | 栈内存溢出的原理(StackOverflowError) |
递归的代码演示 | method()无限调用自身导致崩溃 | 实际开发中需通过条件判断控制递归深度 |
7.斐波那契数列
知识点 | 核心内容 | 重点 |
斐波那契数列定义 | 数列中每个数字是前两个数字之和(从1,1开始) | 起始项定义(通常为F(1)=1, F(2)=1) |
兔子繁殖模型 | 1.新生兔1个月成熟; 2.成熟后每月生1对; 3.无死亡假设 | 第二个月不生兔的时间延迟特性 |
递归算法实现 | method(n) = method(n-1) + method(n-2) | 终止条件必须包含n=1和n=2的情况 |
数列计算示例 | 月份:1→1对, 2→1对, 3→2对, 4→3对, 5→5对, 6→8对 | 第6个月结果8对的推导过程 |
递归调用过程 | 方法自调用时的参数传递机制(月份递减) | 递归树展开时的重复计算问题 |
8.数组反转
知识点 | 核心内容 | 重点 |
数组翻转算法 | 中心思想是数组对称索引位置上的元素互换,通过中间变量实现元素位置交换 | 确定交换终止条件(min >= max)和索引移动规则(min++/max--) |
索引对称原理 | 奇数数组中间元素自对称,偶数数组全部成对交换(图示[1,2,3,4,5,6,7]与[7,6,5,4,3,2,1]索引对应关系) | 奇偶数组的不同处理逻辑 |
元素交换技术 | 使用临时变量temp的三步交换法: 1. temp = arr[min]; 2. arr[min] = arr[max]; 3. arr[max] = temp | 类比水杯交换的具象化理解 |
循环控制逻辑 | for(int min=0,max=arr.length-1; min<max; min++,max--) 复合循环条件写法 | 多语句初始化/迭代的语法特性 |
边界条件处理 | 循环终止条件min < max同时覆盖奇偶两种情况 | 避免偶数数组重复交换 |
9.冒泡排序
知识点 | 核心内容 | 重点 |
冒泡排序定义 | 数组排序方法,通过相邻元素比较和交换实现排序 | 默认升序排序,需理解“相邻元素”指 arr[i] 和 arr[i+1] |
排序过程 | 1. 每轮将最大值“冒泡”到末尾; 2. 比较轮数=数组长度-1,每轮比较次数递减 | 易错点:忽略每轮减少一次比较(已排序部分无需重复比较) |
代码实现关键 | 1. 双重循环(外层控制轮数,内层控制比较次数); 2. 相邻元素交换条件 arr[i] > arr[i+1] | 笔试高频:需默写代码框架及边界条件(如 i < arr.length-1) |
性能特点 | 时间复杂度 O(n²),空间复杂度 O(1) | 对比其他排序:效率低但实现简单,适合小规模数据 |
实例演示 | 数组 [5,4,3,2,1] 的完整排序步骤(4轮比较,每轮次数递减) | 重点观察:最大值如何逐步移动到末尾 |
10.二分查找
知识点 | 核心内容 | 重点 |
二分查找原理 | 通过不断折半缩小查找范围,提升查询效率 | 必须保证数组有序(升序/降序) |
中间索引计算 | mid = (min + max) // 2,动态调整min/max | 初始min=0,max=长度-1,非固定长度/2 |
查找流程 | 1. 比较目标值与mid元素; 2. 大于则min=mid+1; 3. 小于则max=mid-1; 4. 等于则命中 | 终止条件:min > max时未找到 |
效率对比 | 原始遍历:O(n); 二分查找:O(log n) | 数据量越大优势越显著(例:100数据仅需7次比较) |
边界案例 | 目标值在首尾/不存在时索引移动逻辑 | min/max更新需严格±1,避免死循环 |
11.对象数组
知识点 | 核心内容 | 重点 |
对象数组定义 | Person[]数组存储Person对象,数组定义语法与基本类型数组类似 | 数组元素类型与对象类型的匹配关系 |
对象数组初始化 | 创建三个Person对象并存入数组,通过索引赋值 | 数组存储的是对象引用(地址值)而非对象本身 |
数组遍历与属性访问 | 使用for循环遍历数组,通过getter方法获取对象属性 | 遍历得到的是对象引用,需通过引用访问成员方法 |
内存模型解析 | 堆内存中数组元素存储对象引用示意图 | 引用传递与值传递的本质区别 |
类型系统应用 | 接收数组元素必须使用Person类型变量 | 编译期类型检查机制 |
12.对象数组应用
知识点 | 核心内容 | 重点 |
对象数组创建 | 创建Student类数组并初始化三个学生对象 Student[] students = new Student[3] | 匿名对象初始化方式 |
类定义规范 | 定义Student类包含私有属性(name/score)和标准方法(构造器/getter) | 无参/有参构造器同时存在的必要性 |
冒泡排序算法 | 通过嵌套循环实现对象数组排序 | 比较成绩但交换整个对象 |
对象属性访问 | 通过getter方法获取私有属性进行比较 | 直接访问私有属性会导致编译错误 |
数组遍历输出 | 排序后遍历数组输出学生信息 | 注意数组越界问题 |
13.基本类型做参数传递
知识点 | 核心内容 | 重点 |
基本数据类型与引用数据类型的区分 | 基本数据类型包括四类八种(byte、short、int、long、float、double、char、boolean),其余均为引用数据类型 | 如何快速区分:只需记住基本数据类型的范围,其余均为引用类型 |
方法参数传递(基本数据类型) | 基本数据类型作为方法参数传递时,传递的是值而非变量本身,方法内部的修改不影响原始变量 | 易混淆点:误认为方法内部修改会影响原变量值 |
方法调用与栈内存机制 | 方法执行时压栈,运行完毕后弹栈,局部变量仅作用于当前方法栈帧 | 关键理解:方法栈的独立性导致变量作用域隔离 |
14.引用类型作参数传递
知识点 | 核心内容 | 重点 |
引用数据类型作为方法参数传递 | 引用数据类型(如数组)作为参数传递时,传递的是地址值,而非值本身。 | 区分基本数据类型和引用数据类型的参数传递方式;理解为何引用数据类型的修改会影响到原数据。 |
数组在内存中的存储 | 数组在堆内存中存储,变量保存的是数组的地址值。 | 数组的内存分配和地址值的概念;数组如何通过地址值进行访问和修改。 |
方法调用与栈的压栈弹栈 | 方法调用时,会在栈中压栈运行;方法执行完毕后,会弹栈返回。 | 方法调用的栈机制;压栈与弹栈对变量值的影响。 |
方法间参数传递的影响 | 引用数据类型作为参数传递时,方法间的修改会相互影响。 | 引用传递导致的修改共享问题;如何理解并避免不必要的修改。 |
基本数据类型与引用数据类型的区别 | 基本数据类型传递的是值,引用数据类型传递的是地址值。 | 两者在参数传递、内存存储和修改影响上的区别。 |
15.命令行参数
知识点 | 核心内容 | 重点 |
命令行参数 | 指main方法中的String[] args参数,通过命令行或IDE配置传递实参 | 参数传递格式(空格分隔)、IDE配置入口位置 |
参数传递方式 | 1. 命令行运行:java 类名 参数1 参数2; 2. IDEA配置:Run → Edit Configurations → Program Arguments | 参数与类名需空格分隔,参数按顺序对应数组元素 |
实际应用场景 | 临时测试方法功能(如method(String s1, String s2)),避免启动完整项目流程 | 与直接调用方法的区别(灵活性 vs 便捷性) |
IDE操作演示 | 1. 创建类并编写main方法; 2. 通过Edit Configurations设置参数(如哈哈 嘿嘿); 3. 运行后遍历args数组输出结果 | 配置路径易忽略(需通过类名旁箭头进入) |
16.快速生成方法
知识点 | 核心内容 | 重点 |
方法定义与调用顺序 | 初学者需先定义方法再调用,否则报错;熟练者可先调用后定义(通过IDE补全) | Alt+Enter快速生成方法(自动补全参数/返回值) |
IDE智能补全功能 | 使用Alt+Enter自动生成方法: - 无参无返回值(默认private修饰); - 有参无返回值(自动匹配参数类型); - 有返回值(自动推断类型) | 修饰符需手动调整 |
代码抽取为方法 | 选中代码块后按Ctrl+Alt+M快速抽取: - 自动识别依赖变量(如数组参数); - 支持修改方法名/修饰符; - 智能提示返回值需求 | 未选中变量时自动补全参数 |
IDE操作效率技巧 | - 通过快捷键生成代码结构; - 抽取重复逻辑为独立方法 | 需熟悉Alt+Enter与Ctrl+Alt+M组合键 |
17..debug调试
知识点 | 核心内容 | 重点 |
Debug调试概述 | 调试代码的手段,用于监测变量变化和定位错误 | 理解断点作用与调试模式启动方式 |
断点设置 | 在代码行左侧点击添加红色圆点(断点),右键选择Debug启动调试 | 断点可多位置设置,点击消失的特性易忽略 |
调试面板功能 | - 下一步(逐行执行); - 进入方法(跳转至被调用方法内部); - 跳出方法(返回调用处); - 放行(执行当前请求代码但不退出调试); - 结束调试(完全退出) | 放行 vs 结束调试的功能差异(是否保留调试模式) |
变量监控 | 调试过程中实时显示变量值变化(如数组索引赋值过程) | 通过变量面板观察I=3时的数组越界问题 |
调试应用场景 | 示例:购物车功能调试(addCart方法逐行检查变量) | 结合循环调用演示放行按钮的多次触发特性 |