循序渐进学Java 零基础
-韩顺平
第 1 章 内容介绍 1
1.1 本套 JAVA 课程内容 1
1.1.1 课程的三个阶段 1
1.1.2 关于课程的说明 1
1.1.3 课程特色 2
1.2 JAVA 就业方向 2
1.3 JAVA 开发场景举例 1-SSM 3
1.4 JAVA 开发场景举例 2:ANDROID 核心代码 3
1.5 JAVA 开发场景举例 3:大数据-HADOOP 4
1.6 JAVA 的应用领域 4
1.6.1 企业级应用 4
1.6.2 Android 平台应用 5
1.6.3 移动领域应用 5
第 2 章 JAVA 概述 7
2.1 什么是程序 7
2.2 JAVA 诞生小故事 7
2.3 JAVA 技术体系平台 8
2.4 JAVA 重要特点 8
2.5 JAVA 的开发工具 9
2.5.1 工具选择 10
2.6 JAVA 运行机制及运行过程 10
2.6.1 Java 语言的特点:跨平台性 10
2.6.2 Java 核心机制-Java 虚拟机 [JVM java virtual machine] 11
2.7 什么是 JDK,JRE 12
2.7.1 JDK 基本介绍 12
2.7.2 JRE 基本介绍 12
2.7.3 JDK、JRE 和 JVM 的包含关系 12
2.8 下载、安装 JDK 12
2.9 配置环境变量 PATH 13
2.9.1 为什么要配置 path 13
2.9.2 配置环境变量 path 的步骤 13
2.10 安装 JDK 的练习 14
2.10.1 请同学们安装好 JDK,配置好 path 环境变量。可以在控制台下正确的执行, (10min) 14
2.10.2 环境变量配置细节说明: 14
2.11 JAVA 快速入门 14
2.11.1 需求说明 15
2.11.2 开发步骤 15
2.11.3 运行原理示意图 15
2.12 JAVA 开发快速入门 15
2.13 JAVA 开发注意事项和细节说明 17
2.14 老韩聊: 如何快速掌握技术或知识点 18
2.15 JAVA 转义字符 19
2.15.1 Java 常用的转义字符 19
2.15.2 说明 19
2.15.3 课堂练习 21
2.16 初学 JAVA 易犯错误 21
2.17 注释(COMMENT) 22
2.17.1 介绍: 22
2.17.2 Java 中的注释类型 23
2.17.3 单行注释: 23
2.17.4 多行注释: 23
2.17.5 使用细节 23
2.17.6 文档注释: 23
2.17.7 代码演示 24
2.18 JAVA 代码规范 26
2.19 DOS 命令(了解) 26
2.19.1 DOS 介绍 26
2.19.2 相关的知识补充: 相对路径, 绝对路径 27
2.19.3 常用的 dos 命令 28
2.20 本章作业 28
第 3 章 变量 29
3.1 为什么需要变量 29
3.1.1 一个程序就是一个世界 29
3.1.2 变量是程序的基本组成单位 29
3.1.3 简单的原理示意图 30
3.2 变(变化)量(值)的介绍 30
3.2.1 概念 30
3.2.2 变量使用的基本步骤 30
3.3 变量快速入门 31
3.4 变量使用注意事项 32
3.5 程序中 +号的使用 33
3.6 数据类型 33
3.7 整数类型 34
3.7.1 基本介绍 34
3.7.2 案例演示: 34
3.7.3 整型的类型 34
3.7.4 整型的使用细节 IntDetail.java 35
3.8 浮点类型 37
3.8.1 基本介绍 37
3.8.2 案例演示 37
3.8.3 浮点型的分类 37
3.8.4 说明一下 37
3.8.5 浮点型使用细节 FloatDetail.java 37
3.9 JAVA API 文档 40
3.10 字符类型(CHAR) 41
3.10.1 基本介绍 41
3.10.2 案例演示 Char01.java 41
3.10.3 字符类型使用细节 41
3.11 ASCII 码介绍(了解) 44
3.12 UNICODE 编码介绍(了解) 44
3.13 UTF-8 编码介绍(了解) 44
3.14 布尔类型:BOOLEAN 44
3.15 基本数据类型转换 46
3.15.1 自动类型转换 46
3.15.2 自动类型转换注意和细节 46
3.15.3 强制类型转换 49
3.15.4 强制类型转换细节说明 49
3.16 基本数据类型转换-练习题 50
3.17 基本数据类型和 STRING 类型的转换 51
3.17.1 介绍和使用 51
3.17.2 注意事项 53
3.18 本章作业 54
第 4 章 运算符 56
4.1 运算符介绍 56
4.1.1 运算符介绍 56
4.2 算术运算符 56
4.2.1 介绍 56
4.2.2 算术运算符一览 56
4.2.3 案例演示 56
4.2.4 细节说明 58
4.2.5 面试题 59
4.2.6 自增, 自减课堂练习, 看看输出什么 59
4.2.7 课堂练习 2 60
4.3 关系运算符(比较运算符) 62
4.3.1 介绍 62
4.3.2 关系运算符一览 62
4.3.3 案例演示 63
4.3.4 细节说明 64
4.4 逻辑运算符 64
4.4.1 介绍 64
4.4.2 逻辑运算符一览 64
4.4.3 && 和 & 基本规则 65
4.4.4 && 和 & 案例演示 65
4.4.5 && 和 & 使用区别 66
4.4.6 || 和 | 基本规则 67
4.4.7 || 和 | 案例演示 67
4.4.8 || 和 | 使用区别 68
4.4.9 ! 取反 基本规则 68
4.4.10 ! 案例演示 69
4.4.11 ^ 案例演示 69
4.4.12 练习题 1 请写出每题的输出结果 70
4.4.13 练习题 2 请写输出结果 70
4.5 赋值运算符 70
4.5.1 介绍 70
4.5.2 赋值运算符的分类 71
4.5.3 案例演示 71
4.5.4 赋值运算符特点 71
4.6 三元运算符 72
4.6.1 基本语法 72
4.6.2 案例演示 TernaryOperator.java 73
4.6.3 使用细节 TernaryOperatorDetail.java 73
4.6.4 课堂练习 74
4.7 运算符优先级 76
4.8 标识符的命名规则和规范 77
4.8.1 判断下面变量名是否正确 77
4.8.2 标识符命名规范[更加专业] 77
4.9 关键字 78
4.10 保留字 79
4.10.1 介绍 79
4.11 键盘输入语句 79
4.11.1 介绍 79
4.11.2 步骤 : 79
4.11.3 案例演示: 80
4.12 进制(程序员的基本功) 81
4.12.1 进制介绍 81
4.12.2 举例说明 BinaryTest.java 81
4.13 进制的图示 82
4.14 进制的转换(基本功) 83
4.14.1 进制转换的介绍 83
4.15 二进制转换成十进制示例 84
4.16 八进制转换成十进制示例 84
4.17 十六进制转换成十进制示例 84
4.18 十进制转换成二进制 84
4.19 十进制转换成八进制 85
4.20 十进制转换成十六进制 85
4.21 二进制转换成八进制 86
4.22 二进制转换成十六进制 86
4.23 八进制转换成二进制 86
4.24 十六进制转换成二进制 86
4.25 位运算的思考题 87
4.26 二进制在运算中的说明 87
4.27 原码、反码、补码(重点 难点) 88
4.28 位运算符 88
4.28.1 java 中有 7 个位运算(&、|、^、~、>>、<<和 >>>) 88
4.28.2 还有 3 个位运算符 >>、<< 和 >>> , 运算规则: 88
4.28.3 应用案例 BitOperator02.java 89
4.28.4 完成前面的案例 89
4.29 本章作业 89
第 5 章 程序控制结构 91
5.1 程序流程控制介绍 91
5.2 顺序控制 91
5.3 分支控制 IF-ELSE 91
5.3.1 分支控制 if-else 介绍 91
5.3.2 单分支 92
5.4 双分支 93
5.4.1 双分支 95
5.4.2 单分支和双分支练习题 96
5.4.3 多分支 98
多分支的流程图(重要!) 99
5.4.4 多分支 99
5.5 嵌套分支 102
5.5.1 基本介绍 102
5.5.2 基本语法 102
5.5.3 应用案例 102
5.5.4 应用案例 2, 一定自己做 104
5.6 SWITCH 分支结构 104
5.6.1 基本语法 104
5.6.2 流程图 105
5.6.3 快速入门 105
5.6.4 switch 注意事项和细节讨论 107
5.6.5 switch 课堂练习(学员先做) 108
5.6.6 switch 和 if 的比较 112
5.7 FOR 循环控制(!!!) 112
5.7.1 看一个实际需求 113
5.7.2 基本语法 113
5.7.3 for 循环执行流程分析 113
5.7.4 注意事项和细节说明 114
5.7.5 for 循环练习题(学员先做) 115
5.8 WHILE 循环控制 117
5.8.1 基本语法 117
5.8.2 while 循环执行流程分析 118
5.8.3 注意事项和细节说明 120
5.8.4 课堂练习题[学员先做] 120
5.9 DO WHILE 循环控制… 121
5.9.1 基本语法 121
5.9.2 老韩说明: 122
5.9.3 do while 循环执行流程分析…122
5.9.4 注意事项和细节说明 123
5.9.5 课堂练习题【学员先做】 123
5.10 多重循环控制(难点! 重点!) 126
5.10.1 介绍 126
5.10.2 多重循环执行步骤分析: 126
5.10.3 应用实例: 127
5.10.4 经典的打印金字塔 130
5.11 跳转控制语句-BREAK 133
5.11.1 看下面一个需求 133
5.11.2 基本介绍: 133
5.11.3 基本语法: 133
5.11.4 以 while 使用 break 为例,画出示意图 133
5.11.5 快速入门: 134
5.11.6 注意事项和细节说明: 134
5.11.7 课堂练习题: 134
5.12 跳转控制语句-CONTINUE 137
5.12.1 基本介绍: 137
5.12.2 基本语法: 138
5.12.3 以 while 使用 continue 为例,画出示意图 138
5.12.4 快速入门案例 138
5.12.5 细节案例分析和说明: ContinueDetail.java 139
5.13 跳转控制语句-RETURN 139
5.14 本章作业 140
第 6 章 数组、排序和查找 142
6.1 为什么需要数组 142
6.1.1 数组介绍 142
6.1.2 数组快速入门 142
6.2 数组的使用 145
6.2.1 使用方式 2-动态初始化 147
6.2.2 使用方式 3-静态初始化 147
6.3 数组使用注意事项和细节 147
6.4 数组应用案例 149
6.5 数组赋值机制 152
6.6 数组拷贝 152
6.7 数组反转 154
6.8 数组添加/扩容 157
6.9 排序的介绍 160
6.9.1 内部排序: 160
6.9.2 外部排序法: 161
6.10 冒泡排序法 161
6.11 冒泡排序法 161
6.12 查找 167
6.12.1 介绍: 167
6.12.2 案例演示: 167
6.13 多维数组-二维数组 169
6.14 二维数组的使用 169
6.14.1 快速入门案例: 169
6.14.2 使用方式 1: 动态初始化 171
6.14.3 使用方式 2: 动态初始化 173
6.14.4 使用方式 3: 动态初始化-列数不确定 173
6.14.5 使用方式 4: 静态初始化 175
6.14.6 案例: 176
6.15 二维数组的应用案例 177
6.16 二维数组使用细节和注意事项 179
6.17 二维数组课堂练习 180
6.18 本章作业 180
第 7 章 面向对象编程(基础部分) 183
7.1 类与对象 183
7.1.1 看一个养猫猫问题 183
7.1.2 使用现有技术解决 Object01.java 183
7.1.3 现有技术解决的缺点分析 183
7.1.4 一个程序就是一个世界,有很多事物(对象[属性, 行为]) 186
7.1.5 类与对象的关系示意图 186
7.1.6 类与对象的关系示意图 187
7.1.7 快速入门-面向对象的方式解决养猫问题 187
7.1.8 类和对象的区别和联系 187
7.1.9 对象在内存中存在形式(重要的)必须搞清楚。 188
7.1.10 属性/成员变量/字段 188
7.1.11 如何创建对象 191
7.1.12 如何访问属性 191
7.1.13 类和对象的内存分配机制 192
7.2 成员方法 193
7.2.1 基本介绍 193
7.2.2 成员方法快速入门 194
7.2.3 方法的调用机制原理:(重要!-示意图!!!) 197
7.2.4 为什么需要成员方法 197
7.2.5 成员方法的好处 200
7.2.6 成员方法的定义 200
7.2.7 注意事项和使用细节 201
7.2.8 类定义的完善 207
7.2.9 课堂练习题 207
7.3 成员方法传参机制(非常非常重要) 209
7.3.1 基本数据类型的传参机制 210
7.3.2 引用数据类型的传参机制 211
7.3.3 成员方法返回类型是引用类型应用实例 215
7.4 方法递归调用(非常非常重要, 比较难) 218
7.4.1 基本介绍 218
7.4.2 递归能解决什么问题? 218
7.4.3 递归举例 218
7.4.4 递归重要规则 221
7.4.5 课堂练习 221
7.4.6 递归调用应用实例-迷宫问题 224
7.4.7 递归调用应用实例-汉诺塔 230
7.4.8 递归调用应用实例-八皇后问题[同学们先尝试做,后面老师评讲.] 232
7.5 方法重载(OVERLOAD) 233
7.5.1 基本介绍 233
7.5.2 重载的好处 233
7.5.3 快速入门案例 233
7.5.4 注意事项和使用细节 236
7.5.5 课堂练习题 236
7.6 可变参数 240
7.6.1 基本概念 240
7.6.2 基本语法 240
7.6.3 快速入门案例(VarParameter01.java) 240
7.6.4 注意事项和使用细节 242
7.6.5 课堂练习 243
7.7 作用域 245
7.7.1 基本使用 245
7.7.2 注意事项和细节使用 247
7.8 构造方法/构造器 249
7.8.1 看一个需求 250
7.8.2 基本语法 250
7.8.3 基本介绍 250
7.8.4 快速入门 250
7.8.5 注意事项和使用细节 252
7.8.6 课堂练习题 254
7.9 对象创建的流程分析 256
7.9.1 看一个案例 256
7.10 THIS 关键字 257
7.10.1 先看一段代码,并分析问题 257
7.10.2 深入理解 this 260
7.10.3 this 的注意事项和使用细节 261
7.10.4 this 的课堂案例 262
7.11 本章作业 263
第 8 章 面向对象编程(中级部分) 267
8.1 IDE(集成开发环境) -IDEA 267
8.1.1 IDEA 介绍 267
8.2 IDE(集成开发环境) -ECLIPSE 267
8.2.1 Eclipse 介绍 267
8.3 IDE(集成开发环境) -IDEA 的使用 267
8.3.1 IDEA 的安装 267
8.3.2 IDEA 的基本介绍和使用 268
8.3.3 IDEA 使用技巧和经验 268
8.3.4 课堂练习 269
8.3.5 IDEA 常用快捷键 270
8.3.6 模板/自定义模板 270
8.4 包 271
8.4.1 看一个应用场景 271
8.4.2 包的三大作用 271
8.4.3 包基本语法 271
8.4.4 包的本质分析(原理) 271
8.4.5 快速入门 271
8.4.6 包的命名 272
8.4.7 常用的包 272
8.4.8 如何引入包 272
8.4.9 注意事项和使用细节 274
8.5 访问修饰符 275
8.5.1 基本介绍 275
8.5.2 4 种访问修饰符的访问范围 275
8.5.3 使用的注意事项 275
8.6 面向对象编程三大特征 278
8.6.1 基本介绍 278
8.6.2 封装介绍 278
8.6.3 封装的理解和好处 278
8.6.4 封装的实现步骤 (三步) 278
8.7 快速入门案例 279
8.7.1 将构造器和 setXxx 结合 282
8.7.2 课堂练习 283
8.8 面向对象编程-继承 287
8.8.1 为什么需要继承 287
8.8.2 继承基本介绍和示意图 287
8.8.3 继承的基本语法 288
8.8.4 快速入门案例 288
8.8.5 继承给编程带来的便利 290
8.8.6 继承的深入讨论/细节问题 290
8.8.7 继承的本质分析(重要) 295
8.8.8 课堂练习 298
8.9 SUPER 关键字 303
8.9.1 基本介绍 303
8.9.2 基本语法 303
8.9.3 super 给编程带来的便利/细节 309
8.9.4 super 和 this 的比较 309
8.10 方法重写/覆盖(OVERRIDE) 309
8.10.1 基本介绍 309
8.10.2 快速入门 310
8.10.3 注意事项和使用细节 313
8.10.4 课堂练习 313
8.11 面向对象编程-多态 317
8.11.1 先看一个问题 317
8.11.2 多[多种]态[状态]基本介绍 322
8.11.3 多态的具体体现 322
8.11.4 多态快速入门案例 325
8.11.5 多态注意事项和细节讨论 326
8.11.6 课堂练习 331
8.11.7 java 的动态绑定机制(非常非常重要.) 331
8.11.8 多态的应用 334
8.12 OBJECT 类详解 344
8.12.1 equals 方法 344
8.12.2 如何重写 equals 方法 347
8.12.3 课堂练习题 350
8.12.4 hashCode 方法 352
8.12.5 toString 方法 353
8.12.6 finalize 方法 356
8.13 断点调试(DEBUG) 357
8.13.1 一个实际需求 358
8.13.2 断点调试介绍 358
8.13.3 断点调试的快捷键 358
8.13.4 断点调试应用案例 359
8.13.5 断点调试应用案例 359
8.13.6 断点调试课后练习 362
8.14 项目-零钱通 362
8.14.1 项目开发流程说明 362
8.14.2 项目需求说明 362
8.14.3 项目的界面 362
8.14.4 项目代码实现 363
8.14.5 项目代码实现改进 363
8.15 本章作业 363
第 9 章 项目-房屋出租系统 369
9.1 房屋出租系统-需求 369
9.1.1 项目需求说明 369
9.2 房屋出租系统-界面 369
9.2.1 项目界面 - 主菜单 369
9.2.2 项目界面- 新增房源 369
9.2.3 项目界面- 查找房源 369
9.2.4 项目界面- 删除房源 370
9.2.5 项目界面- 修改房源 370
9.2.6 项目界面- 房屋列表 370
9.2.7 项目界面- 退出系统 370
9.3 房屋出租系统-设计(!!) 371
9.4 房屋出租系统-实现 371
9.4.1 准备工具类 Utility,提高开发效率 371
9.4.2 项目功能实现-完成 House 类 371
9.4.3 项目功能实现-显示主菜单和完成退出软件功能 372
9.4.4 项目功能实现-完成显示房屋列表的功能 372
9.4.5 项目功能实现-添加房屋信息的功能 372
9.4.6 项目功能实现-完成删除房屋信息的功能 373
9.4.7 项目功能实现-完善退出确认功能(课堂作业) 373
9.4.8 项目功能实现-完成根据 id 查找房屋信息的功能(课后作业) 374
9.4.9 项目功能实现-完成修改房屋信息的功能(课后作业) 374
第 10 章 面向对象编程(高级部分) 375
10.1 类变量和类方法 375
10.1.1 类变量-提出问题 375
10.1.2 传统的方法来解决 375
10.1.3 类变量快速入门 375
10.1.4 类变量内存布局 377
10.1.5 什么是类变量 378
10.1.6 如何定义类变量 378
10.1.7 如何访问类变量VisitStatic.java 379
10.1.8 类变量使用注意事项和细节讨论 StaticDetail.java 380
10.1.9 类方法基本介绍 381
10.1.10 类方法的调用 381
10.1.11 类方法应用案例 StaticMethod.java 381
10.1.12 类方法经典的使用场景 383
10.1.13 类方法使用注意事项和细节讨论 StaticMethodDetail.java 384
10.1.14 课堂练习 StaticExercise01.java 386
10.1.15 题 2(评讲),看看下面代码有没有错误,如果有错误,就修改,看看输出什么? 386
10.1.16 题 3(评讲),看看下面代码有没有错误,如果有错误,就修改,看看 total 等于多少 4? 387
10.2 理解 MAIN 方法语法 388
10.2.1 深入理解 main 方法 388
10.2.2 特别提示: 389
10.2.3 案例演示 390
10.3 代码块 391
10.3.1 基本介绍 391
10.3.2 基本语法 391
10.3.3 代码块的好处和案例演示 392
10.3.4 代码块使用注意事项和细节讨论 CodeBlockDetail01.java 394
10.3.5 课堂练习题 CodeBlockExercise01.java 404
10.3.6 题 2:下面的代码输出什么? 405
10.4 单例设计模式 406
10.4.1 什么是设计模式 406
10.4.2 什么是单例模式 407
10.4.3 单例模式应用实例 407
10.4.4 饿汉式 VS 懒汉式 412
10.5 FINAL 关键字 412
10.5.1 基本介绍 412
10.5.2 final 使用注意事项和细节讨论 414
10.5.3 final 应用实例 418
10.6 抽象类 419
10.6.1 先看一个问题 Abstract01.java 419
10.6.2 解决之道-抽象类快速入门 421
10.6.3 抽象类的介绍 421
10.6.4 抽象类使用的注意事项和细节讨论 AbstractDetail01.java 421
10.6.5 抽象类使用的注意事项和细节讨论 AbstractDetail02.java 422
10.6.6 课堂练习题 AbstractExercise01.java 5min 练习 424
10.7 抽象类最佳实践-模板设计模式 428
10.7.1 基本介绍 428
10.7.2 模板设计模式能解决的问题 428
10.7.3 最佳实践 428
10.8 接口 432
10.8.1 为什么有接口 432
10.8.2 接口快速入门 432
10.8.3 基本介绍 435
10.8.4 深入讨论 435
10.8.5 注意事项和细节 439
10.8.6 课堂练习 442
10.8.7 实现接口 vs 继承类 443
10.8.8 接口的多态特性 445
10.8.9 课堂练习 InterfaceExercise02.java 450
10.9 内部类 451
10.9.1 基本介绍 451
10.9.2 基本语法 451
10.9.3 快速入门案例 452
10.9.4 内部类的分类 453
10.9.5 局部内部类的使用 LocalInnerClass.java 453
10.9.6 匿名内部类的使用(重要!!!) 455
10.9.7 匿名内部类的最佳实践 463
10.9.8 匿名内部类课堂练习 464
10.9.9 成员内部类的使用 467
10.9.10 静态内部类的使用 StaticInnerClass01.java 470
10.9.11 课堂测试题 472
10.10 卖油翁和老黄牛 473
第 11 章 枚举和注解 475
11.1 先看一个需求 475
11.2 分析问题 477
11.2.1 创建 Season 对象有如下特点 477
11.3 解决方案-枚举 477
11.4 枚举的二种实现方式 477
11.5 自定义类实现枚举-应用案例 477
11.6 自定义类实现枚举-小结 479
11.6.1 小结:进行自定义类实现枚举,有如下特点: 479
11.7 ENUM 关键字实现枚举-快速入门 480
11.7.1 说明 480
11.7.2 enum 关键字实现枚举注意事项 482
11.8 ENUM 关键字实现枚举-课堂练习 483
11.9 ENUM 常 2 用方法说明 484
11.10 ENUM 常用方法应用实例 484
11.11 ENUM 实现接口 489
11.12 注解的理解 491
11.13 基本的 ANNOTATION 介绍 491
11.14 基本的 ANNOTATION 应用案例 491
11.14.1 @Override 注解的案例 Override_.java 491
11.14.2 @Deprecated 注解的案例 Deprecated_.java 494
11.14.3 @SuppressWarnings 注解的案例 SuppressWarnings_.java 495
11.15 JDK 的元 ANNOTATION(元注解, 了解) 499
11.15.1 元注解的基本介绍 499
11.15.2 元注解的种类 (使用不多,了解, 不用深入研究) 499
11.15.3 @Retention 注解 499
11.15.4 @Target 500
11.15.5 @Documented 501
11.15.6 @Inherited 注解 501
11.16 第 10 章作业 501
第 12 章 异常-EXCEPTION 504
12.1 看个实际的问题和一段代码 504
12.2 解决方案-异常捕获 504
12.3 异常介绍 505
12.4 异常体系图一览 506
12.4.1 异常体系图 506
12.4.2 异常体系图的小结 506
12.5 常见的运行时异常 507
12.5.1 常见的运行时异常包括 507
12.5.2 常见的运行时异常举例 507
12.6 编译异常 511
12.6.1 介绍 512
12.6.2 常见的编译异常 512
12.6.3 案例说明 512
12.7 异常课堂练习 513
12.8 异常处理 513
12.8.1 基本介绍 514
12.8.2 异常处理的方式 514
12.8.3 示意图 514
12.9 TRY-CATCH 异常处理 515
12.9.1 try-catch 方式处理异常说明 TryCatch01.java 515
12.9.2 try-catch 方式处理异常-快速入门 515
12.9.3 try-catch 方式处理异常-注意事项 TryCatchDetail.java 516
12.9.4 异常处理课堂练习 521
12.9.5 try-catch-finally 执行顺序小结 523
12.9.6 课后练习题: TryCatchExercise04.java 523
12.10 THROWS 异常处理 525
12.10.1 基本介绍 525
12.10.2 快速入门案例 525
12.10.3 注意事项和使用细节 ThrowsDetail.java 525
12.11 自定义异常 528
12.11.1 基本概念 528
12.11.2 自定义异常的步骤 528
12.11.3 自定义异常的应用实例 CustomException.java 528
12.12 THROW 和 THROWS 的区别 530
12.12.1 一览表 530
12.12.2 测试题-下面的测试输出什么 ThrowException.java 2min 530
12.13 本章作业 530
第 13 章 常用类 533
13.1 包装类 533
13.1.1 包装类的分类 WrapperType.java 533
13.1.2 包装类和基本数据的转换 533
13.1.3 案例演示 Integer01.java 533
13.1.4 课堂测试题 WrapperExercise01.java 2min 535
13.1.5 包装类型和 String 类型的相互转换 WrapperVSString.java 535
13.1.6 Integer 类和 Character 类的常用方法 536
13.1.7 Integer 类面试题 1 WrapperExercise02.java 537
13.1.8 Intege 类面试题总结 539
13.2 STRING 类 540
13.2.1 String 类的理解和创建对象 540
13.2.2 创建 String 对象的两种方式 542
13.2.3 两种创建 String 对象的区别 542
13.2.4 课堂测试题 StringExercise01.java 543
13.3 字符串的特性 546
13.3.1 说明 StringExercise06.java 546
13.3.2 面试题 547
13.4 STRING 类的常见方法 549
13.4.1 说明 549
13.4.2 String 类的常见方法一览 550
13.5 STRINGBUFFER 类 555
13.5.1 基本介绍 555
13.5.2 String VS StringBuffer 557
13.5.3 String 和 StringBuffer 相互转换 557
13.5.4 StringBuffer 类常见方法 558
13.5.5 StringBuffer 类课堂测试题 1 StringBufferExercise01.java 560
13.5.6 StringBuffer 类课后练习 2 561
13.6 STRINGBUILDER 类 563
13.6.1 基本介绍 563
13.6.2 StringBuilder 常用方法 564
13.6.3 String、StringBuffer 和 StringBuilder 的比较 565
13.6.4 String、StringBuffer 和 StringBuilder 的效率测试 565
13.6.5 String、StringBuffer 和 StringBuilder 的选择 567
13.7 MATH 类 567
13.7.1 基本介绍 568
13.7.2 方法一览(均为静态方法) 568
13.7.3 Math 类常见方法应用案例 568
13.8 ARRAYS 类 570
13.8.1 Arrays 类常见方法应用案例 570
13.8.2 Arrays 类课堂练习 579
13.9 SYSTEM 类 584
13.9.1 System 类常见方法和案例 584
13.10 BIGINTEGER 和 BIGDECIMAL 类 586
13.10.1 BigInteger 和 BigDecimal 介绍 586
13.10.2 BigInteger 和 BigDecimal 常见方法 587
13.11 日期类 589
13.11.1 第一代日期类 590
13.11.2 第二代日期类 592
13.11.3 第三代日期类 593
13.11.4 DateTimeFormatter 格式日期类 596
13.11.5 Instant 时间戳 596
13.11.6 第三代日期类更多方法 598
13.12 本章作业 598
第 14 章 集合 600
14.1 集合的理解和好处 600
14.1.1 数组 600
14.1.2 集合 600
14.2 集合的框架体系 600
14.3 COLLECTION 接口和常用方法 602
14.3.1 Collection 接口实现类的特点 602
14.3.2 Collection 接口遍历元素方式 1-使用 Iterator(迭代器) 604
14.3.3 Collection 接口遍历对象方式 2-for 循环增强 610
14.3.4 课堂练习 610
14.4 LIST 接口和常用方法 613
14.4.1 List 接口基本介绍 613
14.4.2 List 接口的常用方法 615
14.4.3 List 接口课堂练习 617
14.4.4 List 的三种遍历方式 [ArrayList, LinkedList,Vector] 619
14.4.5 实现类的课堂练习 2 621
14.5 ARRAYLIST 底层结构和源码分析 624
14.5.1 ArrayList 的注意事项 624
14.5.2 ArrayList 的底层操作机制源码分析(重点,难点.) 624
14.6 VECTOR 底层结构和源码剖析 626
14.6.1 Vector 的基本介绍 626
14.6.2 Vector 和 ArrayList 的比较 629
14.7 LINKEDLIST 底层结构 630
14.7.1 LinkedList 的全面说明 630
14.7.2 LinkedList 的底层操作机制 630
14.7.3 LinkedList 的增删改查案例 634
14.8 ARRAYLIST 和 LINKEDLIST 比较 639
14.8.1 ArrayList 和 LinkedList 的比较 639
14.9 SET 接口和常用方法 639
14.9.1 Set 接口基本介绍 639
14.9.2 Set 接口的常用方法 640
14.9.3 Set 接口的遍历方式 640
14.9.4 Set 接口的常用方法举例 640
14.10 SET 接口实现类-HASHSET 642
14.10.1 HashSet 的全面说明 642
14.10.2 HashSet 案例说明 644
14.10.3 HashSet 底层机制说明 646
14.10.4 HashSet 课堂练习 1 655
14.10.5 HashSet 课后练习 2 658
14.11 SET 接口实现类-LINKEDHASHSET 659
14.11.1 LinkedHashSet 的全面说明 659
14.11.2 LinkedHashSet 课后练习题 LinkedHashSetExercise.java 660
14.12 MAP 接口和常用方法 663
14.12.1 Map 接口实现类的特点 [很实用] 663
14.12.2 Map 接口常用方法 666
14.12.3 Map 接口遍历方法 668
14.12.4 Map 接口课堂练习 672
14.13 MAP 接口实现类-HASHMAP 676
14.13.1 HashMap 小结 676
14.13.2 HashMap 底层机制及源码剖析 676
14.13.3 HashMap 底层机制及源码剖析 677
14.14 MAP 接口实现类-HASHTABLE 683
14.14.1 HashTable 的基本介绍 683
14.14.2 Hashtable 和 HashMap 对比 684
14.15 MAP 接口实现类-PROPERTIES 684
14.15.1 基本介绍 684
14.15.2 基本使用 684
14.16 总结-开发中如何选择集合实现类(记住) 686
14.17 COLLECTIONS 工具类 692
14.17.1 Collections 工具类介绍 692
14.17.2 排序操作: (均为 static 方法) 692
14.17.3 排序操作: (均为 static 方法) 696
14.17.4 查找、替换 696
14.18 本章作业 696
第 15 章 泛型 700
15.1 泛型的理解和好处 700
15.1.1 看一个需求 700
15.1.2 使用传统方法的问题分析 703
15.1.3 泛型快速体验-用泛型来解决前面的问题 703
15.2 泛型的理解和好处 707
15.2.1 泛型的好处 707
15.3 泛型介绍 707
15.4 泛型的语法 711
15.4.1 泛型的声明 711
15.4.2 泛型的实例化 711
15.4.3 泛型使用举例 711
15.4.4 泛型使用的注意事项和细节 GenericDetail.java 715
15.5 泛型课堂类型 719
15.5.1 泛型课堂练习题 719
15.6 自定义泛型 721
15.6.1 自定义泛型类 (难度) 722
15.6.2 自定义泛型接口 727
15.6.3 自定义泛型方法 731
15.6.4 自定义泛型方法 734
15.7 泛型的继承和通配符 735
15.7.1 泛型的继承和通配符说明 GenericExtends.java 735
15.7.2 应用案例 735
15.8 本章作业 739
15.9 JUNIT 739
15.9.1 为什么需要 JUnit 739
15.9.2 基本介绍 740
15.9.3 使用步骤,看老师演示 JUnit_.java 740
第 16 章 坦克大战[1] 742
16.1 坦克大战游戏演示 742
16.1.1 游戏演示 742
16.1.2 文档坦克游戏说明文档.doc 742
16.1.3 为什么写这个项目 742
16.1.4 写项目前的提醒 742
16.1.5 如何讲解这个项目,授课的原则: 743
16.2 JAVA 绘图坐标体系 743
16.2.1 坐标体系-介绍 743
16.2.2 坐标体系-像素 743
16.2.3 介绍-快速入门 744
16.2.4 绘图原理 747
16.2.5 Graphics 类 748
16.2.6 绘出坦克 751
16.2.7 绘图练习 757
16.3 JAVA 事件处理机制 757
16.3.1 事件处理机制-看个问题 757
16.3.2 基本说明 761
16.3.3 请大家看一个示意图 761
16.3.4 机制分析 761
16.3.5 事件处理机制深入理解 761
16.4 坦克大战游戏 762
16.4.1 让你的坦克动起来 762
16.5 本章作业 763
16.5.1 本章作业 763
16.5.2 本章内容小结 774
第 17 章 多线程基础 775
17.1 线程相关概念 775
17.1.1 程序(program) 775
17.1.2 进程 775
17.1.3 什么是线程 775
17.1.4 其他相关概念 776
17.2 线程基本使用 777
17.2.1 创建线程的两种方式 777
17.2.2 线程应用案例 1-继承 Thread 类 777
17.2.3 线程应用案例 2-实现 Runnable 接口 781
17.2.4 线程使用应用案例-多线程执行 785
17.2.5 线程如何理解 788
17.3 继承 THREAD VS 实现 RUNNABLE 的区别 788
17.4 线程终止 792
17.4.1 基本说明 792
17.4.2 应用案例 ThreadExit_.java com.hspedu.exit_ 792
17.5 线程常用方法 793
17.5.1 常用方法第一组 793
17.5.2 注意事项和细节 793
17.5.3 应用案例 ThreadMethod01.java 793
17.5.4 常用方法第二组 793
17.5.5 应用案例 794
17.5.6 课堂练习 794
17.5.7 用户线程和守护线程 796
17.5.8 应用案例 ThreadMethod03.java 796
17.6 线程的生命周期 797
17.6.1 JDK 中用 Thread.State 枚举表示了线程的几种状态 797
17.6.2 线程状态转换图 797
17.6.3 写程序查看线程状态 ThreadState_.java 798
17.7 线程的同步 800
17.7.1 先看一个问题 800
17.8 SYNCHRONIZED 800
17.8.1 线程同步机制 800
17.8.2 同步具体方法-Synchronized 800
17.9 分析同步原理 801
17.10 互斥锁 801
17.10.1 基本介绍 801
17.10.2 使用互斥锁来解决售票问题 802
17.10.3 注意事项和细节 808
17.11 线程的死锁 808
17.11.1 基本介绍 808
17.11.2 应用案例 809
17.11.3 应用案例 DeadLock_.java 809
17.12 释放锁 811
17.12.1 下面操作会释放锁 811
17.12.2 下面操作不会释放锁 811
17.13 本章作业 812
第 18 章 坦克大战【2】 813
18.1 线程-应用到坦克大战 813
18.1.1 坦克大战 0.3 813
18.1.2 坦克大战 0.4 版 813
第 19 章 IO 流 816
19.1 文件 816
19.1.1 什么是文件 816
19.1.2 文件流 816
19.2 常用的文件操作 816
19.2.1 创建文件对象相关构造器和方法 816
19.2.2 获取文件的相关信息 820
19.2.3 应用案例演示 FileInformation.java 820
19.2.4 目录的操作和文件删除 822
19.2.5 应用案例演示 822
19.3 IO 流原理及流的分类 822
19.3.1 Java IO 流原理 822
19.3.2 流的分类 822
19.4 IO 流体系图-常用的类 823
19.4.1 FileInputStream 介绍 824
19.4.2 FileInputStream 应用实例 FileInputStream_.java 824
19.4.3 FileOutputStream 介绍 827
19.4.4 FileOutputStream 应用实例 1 FileOutputStream01.java 828
19.4.5 FileOutputStream 应用实例 2 FileCopy.java 830
19.4.6 FileReader 和 FileWriter 介绍 832
19.4.7 FileReader 相关方法: 833
19.4.8 FileWriter 常用方法 833
19.4.9 FileReader 和 FileWriter 应用案例 FileReader_.java 833
19.5 节点流和处理流 839
19.5.1 基本介绍 839
19.5.2 节点流和处理流一览图 840
19.5.3 节点流和处理流的区别和联系 840
19.5.4 处理流的功能主要体现在以下两个方面: 840
19.5.5 处理流-BufferedReader 和 BufferedWriter 841
19.5.6 处理流-BufferedInputStream 和 BufferedOutputStream 846
19.5.7 介绍 BufferedOutputStream 847
19.5.8 对象流-ObjectInputStream 和 ObjectOutputStream 850
19.5.9 对象流介绍 851
19.5.10 标准输入输出流 854
19.5.11 转换流-InputStreamReader 和 OutputStreamWriter 854
19.6 打印流-PRINTSTREAM 和 PRINTWRITER 858
19.7 PROPERTIES 类 861
19.7.1 看一个需求 861
19.7.2 基本介绍 863
19.7.3 应用案例 863
19.8 本章作业 867
第 20 章 坦克大战【3】 868
20.1 IO 流-应用到坦克大战 868
20.1.1 坦克大战 0.5 版 868
20.1.2 坦克大战 0.6 版 869
20.2 第二个阶段就到这里,大家好好总结 869
第 21 章 网络编程 871
21.1 网络的相关概念 871
21.1.1 网络通信 871
21.1.2 网络 871
21.1.3 ip 地址 871
21.1.4 ipv4 地址分类 872
21.1.5 域名 873
21.1.6 网络通信协议 873
21.1.7 网络通信协议 874
21.1.8 TCP 和 UDP 874
21.2 INETADDRESS 类 875
21.2.1 相关方法 875
21.2.2 应用案例 com.hspedu.api API_.java 875
21.3 SOCKET 875
21.3.1 基本介绍 876
21.4 TCP 网络通信编程 876
21.4.1 基本介绍 876
21.4.2 应用案例 1(使用字节流) 877
21.4.3 应用案例 2(使用字节流) SocketTCP02.java 880
21.4.4 应用案例 3(使用字符流) 884
21.4.5 应用案例 4 TCPFileUploadServer.java TCPFileUploadClient.java 888
21.4.6 netstat 指令 893
21.4.7 TCP 网络通讯不为人知的秘密 894
21.5 UDP 网络通信编程[了解] 894
21.5.1 基本介绍 895
21.5.2 基本流程 895
21.5.3 应用案例 895
21.6 本章作业 899
第 22 章 多用户即时通信系统 901
22.1 QQ 聊天项目演示 901
22.1.1 项目 QQ 演示 901
22.2 为什么选择这个项目 902
22.2.1 项目开发流程 902
22.2.2 需求分析 903
22.2.3 界面设计 903
22.2.4 功能实现-用户登录 905
22.2.5 功能实现-拉取在线用户列表 907
22.2.6 功能实现-无异常退出 907
22.2.7 功能实现-私聊 907
22.2.8 功能实现-群聊 908
22.2.9 功能说明-发文件 909
22.2.10 功能实现-服务器推送新闻 910
22.2.11 多用户即时通信系统 911
第 23 章 反射(REFLECTION) 913
23.1 一个需求引出反射 913
23.1.1 请看下面的问题 913
23.2 反射机制 915
23.2.1 Java Reflection 915
23.2.2 Java 反射机制原理示意图!!! 916
23.2.3 Java 反射机制可以完成 916
23.2.4 反射相关的主要类 917
23.2.5 反射优点和缺点 919
23.2.6 反射调用优化-关闭访问检查 922
23.3 CLASS 类 923
23.3.1 基本介绍 923
23.3.2 Class 类的常用方法 925
23.3.3 应用实例: Class02.java 926
23.4 获取 CLASS 类对象 928
23.5 哪些类型有 CLASS 对象 931
23.5.1 如下类型有 Class 对象 931
23.5.2 应用实例 AllTypeClass.java 931
23.6 类加载 932
23.6.1 基本说明 932
23.6.2 类加载时机 933
23.6.3 类加载过程图 933
23.6.4 类加载各阶段完成任务 933
23.6.5 加载阶段 934
23.6.6 连接阶段-验证 934
23.6.7 连接阶段-准备 935
23.6.8 连接阶段-解析 936
23.6.9 Initialization(初始化) 936
23.7 通过反射获取类的结构信息 938
23.7.1 第一组: java.lang.Class 类 939
23.7.2 第二组: java.lang.reflect.Field 类 939
23.7.3 第三组: java.lang.reflect.Method 类 939
23.7.4 第四组: java.lang.reflect.Constructor 类 939
23.8 通过反射创建对象 946
23.8.1 案例演示 com.hspedu.reflection ReflecCreateInstance.java 947
23.9 通过反射访问类中的成员 949
23.9.1 访问属性 ReflecAccessProperty.java 950
23.9.2 访问方法 ReflecAccessMethod.java 952
23.10 本章作业 955
第 24 章 零基础学 MYSQL 956
24.1 一个问题 956
24.2 解决之道 956
24.2.1 解决之道-文件、数据库 956
24.2.2 MySQL 数据库的安装和配置(安装演示) 956
24.2.3 使用命令行窗口连接 MYSQL 数据库[示意图] 957
24.2.4 操作示意图 957
24.3 NAVICAT 安装和使用 958
24.3.1 介绍 : 图形化 MySQL 管理软件 958
24.3.2 下载&安装&使用 958
24.3.3 演示:使用 Navicat 创建一个数据库 db01, 在 db01 创建一张表 users , 保存 3 个用户 958
24.3.4 老韩扩: 我使用命令行完成 958
24.4 SQLYOG[SQLYOG] 安装和使用 958
24.4.1 介绍 : 图形化 MySQL 管理软件 958
24.4.2 下载&安装&使用 959
24.4.3 演示:使用 SQLyog 创建一个数据库 db01, 在 db01 创建一张表 users , 保存 3 个用户 959
24.5 数据库三层结构-破除 MYSQL 神秘 959
24.6 数据在数据库中的存储方式 960
24.7 SQL 语句分类 960
24.8 创建数据库 961
24.9 查看、删除数据库 962
24.10 备份恢复数据库 962
24.11 备份恢复数据库的表 963
24.12 安装 ECSHOP 数据库 963
24.13 创建表 (按课程大纲顺序) 964
24.14 MYSQL 常用数据类型(列类型) 965
24.14.1 数值型(整数)的基本使用 965
24.14.2 型如何定义一个无符号的整数 966
24.14.3 数值型(bit)的使用 967
24.14.4 数值型(小数)的基本使用 967
24.14.5 字符串的基本使用 969
24.14.6 字符串使用细节 970
24.14.7 日期类型的基本使用 972
24.15 创建表练习 972
24.16 修改表-基本介绍 974
24.17 修改表-课堂练习 974
24.18 数据库 C[CREATE]R[READ]U[UPDATE]D[DELETE]语句 976
24.19 INSERT 语句 976
24.19.1 使用 INSERT 语句向表中插入数据。insert.sql 976
24.19.2 学员练习:使用 insert 语句向表 employee 中插入 2 个员工的信息。 977
24.19.3 细节说明 insertdetail.sql 977
24.20 UPDATE 语句 979
24.20.1 使用 update 语句修改表中数据 979
24.20.2 基本使用 update.sql 979
24.20.3 使用细节: 980
24.21 DELETE 语句 980
24.21.1 使用 delete 语句删除表中数据 980
24.21.2 使用细节 981
24.22 SELECT 语句 981
24.22.1 基本语法 981
24.22.2 注意事项 (创建测试表学生表 ) 981
24.22.3 课堂练习: select01.sql 982
24.22.4 使用表达式对查询的列进行运算 983
24.22.5 在 select 语句中可使用 as 语句 983
24.22.6 练习 select02.sql 983
24.22.7 在 where 子句中经常使用的运算符 983
24.22.8 使用 where 子句,进行过滤查询 select03.sql 984
24.22.9 课堂练习 986
24.22.10 使用 order by 子句排序查询结果 986
24.23 合计/统计函数 987
24.23.1 count 987
24.23.2 sum 989
24.23.3 avg 990
24.23.4 max/min 991
24.23.5 使用 group by 子句对列进行分组 [先创建测试表] 992
24.23.6 使用 having 子句对分组后的结果进行过滤 992
24.24 字符串相关函数 996
24.25 数学相关函数 998
24.26 时间日期相关函数 DATE.SQL 1000
24.27 加密和系统函数 PWD.SQL 1006
24.28 流程控制函数 1007
24.29 MYSQL 表查询 加强… 1010
24.29.1 介绍 1010
24.29.2 分页查询 1011
24.29.3 使用分组函数和分组子句 group by 1013
24.29.4 数据分组的总结 1015
24.30 MYSQL 多表查询 1015
24.30.1 问题的引出(重点,难点) 1015
24.30.2 说明 1016
24.30.3 多表查询练习 many_tab.sql 1016
24.30.4 自连接 1017
24.31 MYSQL 表子查询 1018
24.31.1 什么是子查询 subquery.sql 1018
24.31.2 单行子查询 1018
24.31.3 请思考:如何显示与 SMITH 同一部门的所有员工? 1018
24.31.4 多行子查询 1019
24.31.5 子查询当做临时表使用 练习题 subquery.sql 1020
24.31.6 在多行子查询中使用 all 操作符 1021
24.31.7 在多行子查询中使用 any 操作符 1023
24.31.8 多列子查询 manycolumn.sql 1024
24.31.9 在 from 子句中使用子查询 subquery03.sql 1026
24.31.10 在 from 子句中使用子查询—课堂小练习 1026
24.32 表复制 1028
24.32.1 自我复制数据(蠕虫复制) 1028
24.33 合并查询 1031
24.33.1 介绍 1031
24.34 MYSQL 表外连接 1032
24.34.1 提出一个问题 1032
24.34.2 外连接 1032
24.34.3 课堂练习 1036
24.35 MYSQL 约束 1036
24.35.1 基本介绍 1037
24.35.2 primary key(主键)-基本使用 1037
24.35.3 not null(非空) 1040
24.35.4 unique(唯一) 1040
24.35.5 foreign key(外键) 1041
24.35.6 check 1044
24.35.7 商店售货系统表设计案例[先练,再评 10min] 1045
24.36 自增长 1047
24.36.1 自增长基本介绍 一个问题 1047
24.36.2 自增长使用细节 1048
24.37 MYSQL 索引 1051
24.37.1 索引快速入门 1051
24.37.2 索引的原理 1056
24.37.3 索引的类型 1056
24.37.4 索引使用 1056
24.37.5 索引课堂练习 1059
24.37.6 小结: 哪些列上适合使用索引 1059
24.38 MYSQL 事务 1060
24.38.1 什么是事务 1060
24.38.2 事务和锁 1060
24.38.3 回退事务 1062
24.38.4 提交事务 1062
24.38.5 事务细节讨论 transaction_detail.sql 1062
24.39 MYSQL 事务隔离级别 1063
24.39.1 事务隔离级别介绍 1063
24.39.2 查看事务隔离级别 1064
24.39.3 事务隔离级别 1064
24.39.4 mysql 的事务隔离级 案例… 1065
24.39.5 设置事务隔离级别 1065
24.40 MYSQL 事务 ACID 1067
24.40.1 事务的 acid 特性 1067
24.40.2 事务的课堂练习 [一定要自己去练习,体会] 1067
24.41 MYSQL 表类型和存储引擎 1067
24.41.1 基本介绍 1068
24.41.2 主要的存储引擎/表类型特点 1068
24.41.3 细节说明 1068
24.41.4 三种存储引擎表使用案例 1069
24.41.5 如何选择表的存储引擎 1070
24.41.6 修改存储引擎 1070
24.42 视图(VIEW) 1071
24.42.1 看一个需求 1071
24.42.2 基本概念 1071
24.42.3 视图的基本使用 1072
24.42.4 完成前面提出的需求 view.sql 1072
24.42.5 视图细节讨论 1074
24.42.6 视图最佳实践 1075
24.42.7 视图课堂练习(学员练习) 1075
24.43 MYSQL 管理 1076
24.43.1 Mysql 用户 1076
24.43.2 创建用户 1077
24.43.3 删除用户 1077
24.43.4 用户修改密码 1077
24.43.5 mysql 中的权限 1077
24.43.6 给用户授权 1078
24.43.7 回收用户授权 1079
24.43.8 权限生效指令 1079
24.43.9 课堂练习题 grant.sql 1079
24.43.10 细节说明 manage_detail.sql 1081
24.44 本章作业 1082
第 1 章 内容介绍
1 本套 Java 课程内容
1.2关于课程的说明
关于这套课程,老韩要给小伙伴们说:
以培养编程思想、提升编程能力为核心目标,达到能分析业务需求,并能用代码实现水平
抛弃传统的以强灌知识点授课方式,每个阶段都有多个项目把知识点真正应用到项目中, 小伙伴在学习过程中有满 满成就感,充分体会编程乐趣
课程成完整体系,超全,超详细。
充分考虑零基础小伙伴,通俗易懂
宁肯慢点,也不遗漏细节。[包括软件安装、开发环境配置和使用]
项目是从小到大的过程,项目分解成不同的功能模块,随功能的增加,将知识点融入到项目,整个过程是循序渐进的。 让大家轻松的学,高效的学。
为减轻小伙伴学习压力,将课程分为三个阶段,小伙伴可以根据当前水平,选择从某个阶段开始学习
零基础的小伙伴,老韩强烈建议从第一阶段开始学习.
因为课程内容非常全,录制周期长,老韩也会根据实际情况做微调
1.2 Java 就业方向
1.3 Java 开发场景举例 1-SSM
1.4 Java 开发场景举例 2:Android 核心代码
1.5 Java 开发场景举例 3 :大数据-hadoop
1.6 Java 的应用领域
1.6. 1企业级应用
主要指复杂的大企业的软件系统、各种类型的网站。应用领域包括金融、电信、交通、电子商务等。
1.6.2Android 平台应用
Android 应用程序使用 Java 语言编写。Android 开发水平的高低很大程度上取决于 Java语言核心能力是否扎实。
1.6.3移动领域应用
主要表现在消费和嵌入式领域,是指在各种小型设备上的应用,包括机顶盒、车载的大屏影音娱乐设备、汽车通信 设备、扫码的 POS 机等。
第 2 章 Java 概述
2. 1 什么是程序
程序:计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合
举例说明:
2.2 Java 诞生小故事
2.3 Java 技术体系平台
2.4 Java 重要特点
Java 语言是面向对象的(oop)
Java 语言是健壮的。Java 的强类型机制、异常处理、垃圾的自动收集等是 Java程序健壮性的重要保证
Java 语言是跨平台性的。[即: 一个编译好的.class 文件可以在多个系统下运行,这种特性称为跨平台]
Java 语言是解释型的[了解]
解释性语言:javascript,PHP, java 编译性语言: c / c++
区别是:解释性语言,编译后的代码,不能直接被机器执行,需要解释器来执行, 编译性语言, 编译后的代码, 可 以直接被机器执行, c /c++
2.5 Java 的开发工具
2.5. 1工具选择
如何选择开发工具
我们先选择用文本编辑器本 sublime ,到大家对java 有一定了解后,我们再使用 IDEA 和 Eclipse 开发工具。
这是为什么呢
更深刻的理解java 技术,培养代码感。【面试时,往往程序员手写代码】
有利于公司面试。
2.6 Java 运行机制及运行过程
2.6. 1Java 语言的特点:跨平台性
2.6.2Java 核心机制-Java 虚拟机 [JVMjava virtual machine]
基本介绍
2.7 什么是 JDK ,JRE
2.7. 1JDK 基本介绍
2.9 配置环境变量 path
2.9. 1为什么要配置 path
2.9.2配置环境变量 path 的步骤
10 安装 JDK 的练习
10.2 环境变量配置细节说明:
11 Java 快速入门
11.2 开发步骤
11.3 运行原理示意图
12 Java 开发快速入门
//这是java 的快速入门, 演示java 的开发步骤
//对代码的相关说明
//1. public class Hello 表示 Hello 是一个类,是一个 public 公有的类
//2. Hello { } 表示一个类的开始和结束
//3. public static void main(String[] args) 表示一个主方法, 即我们程序的入口
//4. main() {} 表示方法的开始和结束
//5. System.out.println(“hello,world~”); 表示输出"hello,world~"到屏幕
//6. ;表示语句结束
public class Hello {
//编写一个 main 方法
public static void main(String[] args) {
System.out.println(“韩顺平教育 hello”);
}
}
//一个源文件中最多只能有一个 public 类。其它类的个数不限。[演示]
//Dog 是一个类
//编译后,每一个类,都对于一个.class
class Dog {
//一个源文件中最多只能有一个 public 类。其它类的个数不限,也可以将 main 方法写在非 public 类中, //然后指定运行非 public 类,这样入口方法就是非 public 的 main 方法
public static void main(String[] args) {
System.out.println(“hello, 小狗狗~”);
}
}
class Tiger {
public static void main(String[] args) {
System.out.println(“hello, 小老虎~”);
}
}
13 Java 开发注意事项和细节说明
14 老韩聊: 如何快速掌握技术或知识点
15 Java 转义字符
15.2 说明
应用实例
//演示转义字符的使用
public class ChangeChar {
//编写一个 main 方法
public static void main(String[] args) {
//\t :一个制表位,实现对齐的功能
System.out.println(“北京\t 天津\t 上海”);
// \n :换行符
System.out.println(“jack\nsmith\nmary”);
// \ :一个\ \
System.out.println(“C:\Windows\System32\cmd.exe”);
// " :一个"
System.out.println(“老韩说:“要好好学习java,有前途””);
// ’ :一个’
System.out.println(“老韩说:‘要好好学习java,有前途’”);
// \r :一个回车 System.out.println(“韩顺平教育\r 北京”);
// 解读
// 1. 输出 韩顺平教育
// 2. \r 表示回车
System.out.println(“韩顺平教育\r 北京”); // 北京平教育
}
}
public class ChangeCharExer01 {
//编写一个 main 方法
public static void main(String[] args) {
//完成代码
System.out.println(“书名\t 作者\t 价格\t 销量\n 三国\t 罗贯中\t120\t1000”);
//示意 => 可读性很好
//下面代码完成 两个数相加
//定义变量
int n1 = 10;
int n2 = 30;
//求和
int sum = n1 + n2;
//输出结果
System.out.println(“结果=” + sum);
}
}
2. 16 初学java 易犯错误
用于注解说明解释程序的文字就是注释,注释提高了代码的阅读性 (可读性) ;注释是一个程序员必须要具有的良 好编程习惯。将自己的思想通过注释先整理出来,再用代码去体现。 [举例]
17.3 单行注释:
基本格式
格式: //注释文字
17.4 多行注释:
基本格式
格式: /* 注释文字 */
17.5 使用细节
17.6 文档注释:
17.7 代码演示
//演示注释使用
public class Comment01 {
//编写一个 main 方法
public static void main(String[] args) {
//单行注释
//多行注释
/* 示意 => 可读性很好
下面代码完成 两个数相加
定义变量
注释
注释
int n1 = 10;…
System.out.println(“ok~~”);
*/
int n1 = 10;
int n2 = 30;
//求和
int sum = n1 + n2;
//输出结果
System.out.println(“结果=” + sum);
}
}
/**
//编写一个 main 方法
public static void main(String[] args) {
//选中,然后输入 tab 整体右移
//选中,然后输入 shift+tab 整体左移
int n1 = 1 + 2;
int n2 = 5 + 10;
int n2 = 1 + 3 * 34;
}
}
18 Java 代码规范
19 DOS 命令(了解)
19.2 相关的知识补充: 相对路径, 绝对路径
19.3 常用的 dos 命令
第 3 章 变量
3. 1 为什么需要变量
3. 1. 1 一个程序就是一个世界
1.2变量是程序的基本组成单位
1.3简单的原理示意图
3.2 变(变化)量(值)的介绍
3.2. 1概念
变量相当于内存中一个数据存储空间的表示,你可以把变量看做是一个房间的门牌号,通过门牌号我们可以找到房
间,而通过变量名可以访问到变量(值)。
3.2.2变量使用的基本步骤
//也可以一步到位[int a = 60; 通常我们是一步完成]
3.3 变量快速入门
变量使用入门案例
看演示并对代码进行说明, 演示记录 人的信息的代码
public class Var02 {
//编写一个 main 方法
public static void main(String[] args) {
//记录人的信息
int age = 30;
double score = 88.9;
char gender = ‘男’;
String name = “king”;
//输出信息, 快捷键
System.out.println(“人的信息如下:”);
System.out.println(name);
System.out.println(age);
System.out.println(score);
System.out.println(gender);
}
}
3.4 变量使用注意事项
public class VarDetail {
//编写一个 main 方法
public static void main(String[] args) {
//变量必须先声明,后使用, 即有顺序
int a = 50;//int
System.out.println(a);//50
//该区域的数据/值可以在同一类型范围内不断变化
//a = “jack”; //×
a = 88; //对
System.out.println(a);//88
//变量在同一个作用域内不能重名
//int a = 77;//错误
}
}
class Dog {
public static void main(String[] args) {
int a = 666;//对
}
}
3.5 程序中 +号的使用
3.6 数据类型
每一种数据都定义了明确的数据类型,在内存中分配了不同大小的内存空间(字节)。
上图说明 [老韩要求小伙伴,背下来!!!]
3.7.4整型的使用细节 IntDetail.java
public class IntDetail {
//编写一个 main 方法
public static void main(String[] args) {
//Java 的整型常量 (具体值) 默认为 int 型,声明 long 型常量须后加‘l’或‘L’
int n1 = 1;//4 个字节
//int n2 = 1L;//对不对?不对
long n3 = 1L;//对
}
}
3.8 浮点类型
3.8. 1基本介绍
Java 的浮点类型可以表示一个小数,比如 123.4 ,7.8 ,0. 12 等等
3.8.2案例演示
3.8.3浮点型的分类
3.8.4说明一下
public class FloatDetail {
//编写一个 main 方法
public static void main(String[] args) {
//Java 的浮点型常量(具体值)默认为 double 型,声明 float 型常量,须后加‘f’或‘F’
//float num1 = 1. 1; //对不对?错误
float num2 = 1. 1F; //对的
double num3 = 1. 1; //对
double num4 = 1. 1f; //对
//十进制数形式:如:5. 12 512.0f .512 (必须有小数点)
double num5 = . 123; //等价 0. 123
System.out.println(num5);
//科学计数法形式:如:5. 12e2 [5. 12 * 10 的 2 次方 ] 5. 12E-2 []
System.out.println(5. 12e2);//512.0
System.out.println(5. 12E-2);//0.0512
//通常情况下,应该使用 double 型,因为它比 float 型更精确。
//[举例说明]double num9 = 2. 1234567851;float num10 = 2. 1234567851F;
double num9 = 2. 1234567851;
float num10 = 2. 1234567851F;
System.out.println(num9);
System.out.println(num10);
//浮点数使用陷阱: 2.7 和 8. 1 / 3 比较
//看看一段代码
double num11 = 2.7;
double num12 = 2.7; //8. 1 / 3; //2.7
System.out.println(num11);//2.7
System.out.println(num12);//接近 2.7 的一个小数,而不是 2.7
//得到一个重要的使用点: 当我们对运算结果是小数的进行相等判断是,要小心
//应该是以两个数的差值的绝对值,在某个精度范围类判断
if( num11 == num12) {
System.out.println(“num11 == num12 相等”);
}
//正确的写法 , ctrl + / 注释快捷键, 再次输入就取消注释
if(Math.abs(num11 - num12) < 0.000001 ) {
System.out.println(“差值非常小,到我的规定精度,认为相等…”);
}
// 可以通过java API 来看 下一个视频介绍如何使用 API
System.out.println(Math.abs(num11 - num12));
//细节:如果是直接查询得的的小数或者直接赋值,是可以判断相等
}
}
3.9 Java API 文档
public class CharDetail {
//编写一个 main 方法
public static void main(String[] args) {
//在java 中,char 的本质是一个整数,在默认输出时,是 unicode 码对应的字符
//要输出对应的数字,可以(int)字符
char c1 = 97;
System.out.println(c1); // a
char c2 = ‘a’; //输出’a’ 对应的 数字
System.out.println((int)c2);
char c3 = ‘韩’;
System.out.println((int)c3);//38889
char c4 = 38889;
System.out.println(c4);//韩
//char 类型是可以进行运算的,相当于一个整数,因为它都对应有 Unicode 码.
System.out.println(‘a’ + 10);//107
//课堂小测试
char c5 = ‘b’ + 1;//98+ 1==> 99
System.out.println((int)c5); //99
System.out.println(c5); //99->对应的字符->编码表 ASCII(规定好的)=>c
}
}
11 ASCII 码介绍(了解)
12 Unicode 编码介绍(了解)
13 UTF-8 编码介绍(了解)
14 布尔类型:boolean
public class Boolean01 {
//编写一个 main 方法
public static void main(String[] args) {
//演示判断成绩是否通过的案例
//定义一个布尔变量
boolean isPass = true;//
if(isPass == true) {
System.out.println(“考试通过,恭喜”);
} else {
System.out.println(“考试没有通过,下次努力”);
}
}
}
15 基本数据类型转换
15.2 自动类型转换注意和细节
//自动类型转换细节
public class AutoConvertDetail {
//编写一个 main 方法
public static void main(String[] args) {
//细节 1 : 有多种类型的数据混合运算时,
//系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算
int n1 = 10; //ok
//float d 1 = n1 + 1. 1;//错误 n1 + 1. 1 => 结果类型是 double
//double d 1 = n1 + 1. 1;//对 n1 + 1. 1 => 结果类型是 double
float d 1 = n1 + 1. 1F;//对 n1 + 1. 1 => 结果类型是 float
//细节 2: 当我们把精度(容量)大 的数据类型赋值给精度(容量)小 的数据类型时,
//就会报错,反之就会进行自动类型转换。
//
//int n2 = 1. 1;//错误 double -> int
//细节 3: (byte, short) 和 char 之间不会相互自动转换
//当把具体数赋给 byte 时,( 1)先判断该数是否在 byte 范围内,如果是就可以
byte b 1 = 10; //对 , - 128- 127
// int n2 = 1; //n2 是 int
// byte b2 = n2;//错误,原因: 如果是变量赋值,判断类型
//
// char c1 = b1; //错误, 原因 byte 不能自动转成 char
//
//
//细节 4:byte ,short ,char 他们三者可以计算,在计算时首先转换为 int 类型
byte b2 = 1;
byte b3 = 2;
short s1 = 1;
//short s2 = b2 + s1;//错, b2 + s1 => int
int s2 = b2 + s1;//对, b2 + s1 => int
//byte b4 = b2 + b3; //错误: b2 + b3 => int
//
//boolean 不参与转换
boolean pass = true;
//int num100 = pass;// boolean 不参与类型的自动转换
//自动提升原则: 表达式结果的类型自动提升为 操作数中最大的类型
//看一道题
byte b4 = 1;
short s3 = 100;
int num200 = 1;
float num300 = 1. 1F;
double num500 = b4 + s3 + num200 + num300; //float -> double
}
}
15.3 强制类型转换
介绍
自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符 ( ),但可能造成 精度降低或溢出,格外要注意。
案例演示 ForceConvert.java
15.4 强制类型转换细节说明
public class ForceConvertDetail {
//编写一个 main 方法
public static void main(String[] args) {
//演示强制类型转换
//强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
//int x = (int)103.5+61.5;//编译错误: double -> int
int x = (int)(103.5+61.5);// (int)44.0 -> 44
System.out.println(x);//44
char c1 = 100; //ok
int m = 100; //ok
//char c2 = m; //错误
char c3 = (char)m; //ok
System.out.println(c3);//100 对应的字符, d 字符
}
}
3. 16 基本数据类型转换-练习题
public class StringToBasic {
//编写一个 main 方法
public static void main(String[] args) {
//基本数据类型->String
int n1 = 100;
float f1 = 1. 1F;
double d 1 = 4.5;
boolean b 1 = true;
String s1 = n1 + “”;
String s2 = f1 + “”;
String s3 = d 1 + “”;
String s4 = b1 + “”;
System.out.println(s1 + " " + s2 + " " + s3 + " " + s4);
//String->对应的基本数据类型
String s5 = “123”;
//会在 OOP 讲对象和方法的时候回详细
//解读 使用 基本数据类型对应的包装类,的相应方法,得到基本数据类型
int num1 = Integer.parseInt(s5);
double num2 = Double.parseDouble(s5);
float num3 = Float.parseFloat(s5);
long num4 = Long.parseLong(s5);
byte num5 = Byte.parseByte(s5);
boolean b = Boolean.parseBoolean(“true”);
short num6 = Short.parseShort(s5);
System.out.println(“===================”);
System.out.println(num1);//123
System.out.println(num2);//123.0
System.out.println(num3);//123.0
System.out.println(num4);//123
System.out.println(num5);//123
System.out.println(num6);//123
System.out.println(b);//true
//怎么把字符串转成字符 char -> 含义是指 把字符串的第一个字符得到
//解读 s5.charAt(0) 得到 s5 字符串的第一个字符 ‘1’
System.out.println(s5.charAt(0));
}
}
案例演示: StringToBasicDetail.java
,比如 我们可以把 “123” , 转成一
/**
//编写一个 main 方法
public static void main(String[] args) {
String str = “hello”;
//转成 int
int n1 = Integer.parseInt(str);
System.out.println(n1);
}
}
第 4 章 运算符
4. 1 运算符介绍
4. 1. 1运算符介绍
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
4.2.3案例演示
/**
//编写一个 main 方法
public static void main(String[] args) {
// /使用
System.out.println( 10 / 4); //从数学来看是 2.5, java 中 2
System.out.println( 10.0 / 4); //java 是 2.5
// 注释快捷键 ctrl + /, 再次输入 ctrl + / 取消注释
double d = 10 / 4;//java 中 10 / 4 = 2, 2=>2.0
System.out.println(d);// 是 2.0
// % 取模 ,取余
// 在 % 的本质 看一个公式!!! a % b = a - a / b * b
// - 10 % 3 => - 10 - (- 10) / 3 * 3 = - 10 + 9 = - 1
// 10 % -3 = 10 - 10 / (-3) * (-3) = 10 - 9 = 1
// - 10 % -3 = (- 10) - (- 10) / (-3) * (-3) = - 10 + 9 = - 1
System.out.println( 10 % 3); //1
System.out.println(- 10 % 3); // - 1
System.out.println( 10 % -3); //1
System.out.println(- 10 % -3);//- 1
//++的使用
//
int i = 10;
i++;//自增 等价于 i = i + 1; => i = 11
++i;//自增 等价于 i = i + 1; => i = 12
System.out.println(“i=” + i);//12
/*
作为表达式使用
前++:++i 先自增后赋值
后++:i++先赋值后自增
*/
int j = 8;
//int k = ++j; //等价 j=j+1;k=j;
int k = j++; // 等价 k =j;j=j+1;
System.out.println(“k=” + k + “j=” + j);//8 9
}
}
4.2.4细节说明
4.2.5面试题
4.2.6自增,自减课堂练习, 看看输出什么
//练习
public class ArithmeticOperatorExercise01 {
//编写一个 main 方法
public static void main(String[] args) {
// int i = 1;//i-> 1
// i = i++; //规则使用临时变量: ( 1) temp=i;(2) i=i+1;(3)i=temp;
// System.out.println(i); // 1
// int i=1;
// i=++i; //规则使用临时变量: ( 1) i=i+1;(2) temp=i;(3)i=temp;
// System.out.println(i); //2
//
// 测试输出
int i1 = 10;
int i2 = 20;
int i = i1++;
System.out.print(“i=”+i);//10
System.out.println(“i2=”+i2);//20
i = --i2;
System.out.print(“i=”+i);//19
System.out.println(“i2=”+i2);//19
}
}
4.2.7课堂练习 2
//ArithmeticOperatorExercise02.java
//课堂练习
public class ArithmeticOperatorExercise02 {
//编写一个 main 方法
public static void main(String[] args) {
//1.需求:
//假如还有 59 天放假,问:合 xx 个星期零 xx 天
//2.思路分析
//(1) 使用 int 变量 days 保存 天数
//(2) 一个星期是 7 天 星期数 weeks : days / 7 零 xx 天 leftDays days % 7
//(3) 输出
//3.走代码
int days = 25911;
int weeks = days / 7;
int leftDays = days % 7;
System.out.println(days + “天 合” + weeks + “星期零”
//定义一个变量保存华氏温度,华氏温度转换摄氏温度的公式为
//:5/9*(华氏温度- 100),请求出华氏温度对应的摄氏温度
//
//2 思路分析
//(1) 先定义一个 double huaShi 变量保存 华氏温度
//(2) 根据给出的公式,进行计算即可 5/9*(华氏温度- 100)
// 考虑数学公式和java 语言的特性
//(3) 将得到的结果保存到 double sheShi
//3 走代码
double huaShi = 1234.6;
double sheShi = 5.0 / 9 * (huaShi - 100);
System.out.println(“华氏温度” + huaShi
}
}
4.3 关系运算符(比较运算符)
4.3. 1介绍
4.3.3案例演示
案例演示关系运算符的使用(RelationalOperator.java)。
//演示关系运算符的使用
//
public class RelationalOperator {
//编写一个 main 方法
public static void main(String[] args) {
int a = 9; //老韩提示: 开发中,不可以使用 a, b
int b = 8;
System.out.println(a > b); //T
System.out.println(a >= b); //T
System.out.println(a <= b); //F
System.out.println(a < b);//F
System.out.println(a == b); //F
System.out.println(a != b); //T
boolean flag = a > b; //T
System.out.println(“flag=” + flag);
}
}
4.3.4细节说明
说明逻辑运算规则:
a&b : & 叫逻辑与:规则:当 a 和 b 同时为 true ,则结果为 true, 否则为 false
a&&b : && 叫短路与:规则:当 a 和 b 同时为 true ,则结果为 true,否则为 false
a|b : | 叫逻辑或,规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false
a||b : || 叫短路或,规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false
!a : 叫取反,或者非运算。当 a 为 true, 则结果为 false, 当 a 为 false 是,结果为 true
a^b: 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false
4.4.3 && 和 & 基本规则
名称 语法 特点
短路与&& 条件 1&&条件 2 两个条件都为true ,结果为 true,否则 false
逻辑与& 条件 1&条件 2 两个条件都为true ,结果为 true,否则 false
4.4.4 && 和 & 案例演示
案例演示&& 和 & 运算符的使用(LogicOperator01.java)。
/**
public class LogicOperator01 {
//编写一个 main 方法
public static void main(String[] args) {
//&&短路与 和 & 案例演示
int age = 50;
if(age > 20 && age < 90) {
System.out.println(“ok 100”);
}
//&逻辑与使用
if(age > 20 & age < 90) {
System.out.println(“ok200”);
}
//区别
int a = 4;
int b = 9;
//对于&&短路与而言,如果第一个条件为 false ,后面的条件不再判断
//对于&逻辑与而言,如果第一个条件为 false ,后面的条件仍然会判断
if(a < 1 & ++b < 50) {
System.out.println(“ok300”);
}
System.out.println(“a=” + a + " b=" + b);// 4 10
}
}
4.4.5 && 和 & 使用区别
&&短路与:如果第一个条件为 false ,则第二个条件不会判断,最终结果为 false ,效率高
& 逻辑与:不管第一个条件是否为false ,第二个条件都要判断,效率低
开发中, 我们使用的基本是使用短路与&&, 效率高
4.4.6 || 和 | 基本规则
名称 语法 特点
短路或|| 条件 1||条件 2 两个条件中只要有一个成立,结果为 true,否则为 false
|逻辑或 条件 1|条件 2 只要有一个条件成立,结果为 true,否则为 false
4.4.7 || 和 | 案例演示
案例演示&& || !运算符的使用( i t j )
//演示| || 使用
public class LogicOperator02 {
//编写一个 main 方法
public static void main(String[] args) {
//||短路或 和 |逻辑或 案例演示
//|| 规则: 两个条件中只要有一个成立,结果为 true,否则为 false
//| 规则: 两个条件中只要有一个成立,结果为 true,否则为 false
int age = 50;
if(age > 20 || age < 30) {
System.out.println(“ok 100”);
}
//&逻辑与使用
if(age > 20 | age < 30) {
System.out.println(“ok200”);
}
//看看区别
//(1)||短路或:如果第一个条件为 true,
//则第二个条件不会判断,最终结果为true ,效率高
//(2)| 逻辑或:不管第一个条件是否为true ,第二个条件都要判断,效率低
int a = 4;
int b = 9;
if( a > 1 || ++b > 4) { // 可以换成 | 测试
System.out.println(“ok300”);
}
System.out.println(“a=” + a + " b=" + b); //4 10
}
}
4.4.8 || 和 | 使用区别
! 非 (取反) !条件 如果条件本身成立,结果为 false ,否则为true
4.4. 10 ! 案例演示
案例演示 !运算符的使用(InverseOperator.java)。
//!和^案例演示
public class InverseOperator {
//编写一个 main 方法
public static void main(String[] args) {
//! 操作是取反 T->F , F -> T
System.out.println(60 > 20); //T
System.out.println(!(60 > 20)); //F
//a^b: 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false
boolean b = (10 > 1) ^ ( 3 > 5);
System.out.println(“b=” + b);//T
}
}
4.4. 11 ^ 案例演示
a^b: 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false
^逻辑异或,System.out.println( (4 < 1) ^ (6 > 3) ); // ?
4.4. 12 练习题 1 请写出每题的输出结果
4.4. 13 练习题 2 请写输出结果
4.5 赋值运算符
4.5. 1介绍
赋值运算符就是将某个运算后的值,赋给指定的变量。
4.5.2赋值运算符的分类
基本赋值运算符 = int a = 10;
复合赋值运算符
+= ,-= ,*= , /= ,%= 等 , 重点讲解一个 += ,其它的使用是一个道理
a += b; [等价 a = a + b; ]
a -= b; [等价 a = a - b; ]
4.5.3案例演示
案例演示赋值运算符的基本使用。AssignOperator.java
4.5.4赋值运算符特点
//演示赋值运算符的使用
public class AssignOperator {
//编写一个 main 方法
public static void main(String[] args) {
int n1 = 10;
n1 += 4;// n1 = n1 + 4;
System.out.println(n1); // 14
n1 /= 3;// n1 = n1 / 3;//4
System.out.println(n1); // 4
//复合赋值运算符会进行类型转换
byte b = 3;
b += 2; // 等价 b = (byte)(b + 2);
b++; // b = (byte)(b+1);
}
}
4.6 三元运算符
4.6. 1基本语法
条件表达式 ? 表达式 1: 表达式 2;
运算规则:
4.6.2案例演示 TernaryOperator.java
//三元运算符使用
public class TernaryOperator {
//编写一个 main 方法
public static void main(String[] args) {
int a = 10;
int b = 99;
// 解读
// 1. a > b 为 false
// 2. 返回 b–, 先返回 b 的值,然后在 b- 1
// 3. 返回的结果是 99
int result = a > b ? a++ : b–;
System.out.println(“result=” + result);
System.out.println(“a=” + a);
System.out.println(“b=” + b);
}
}
4.6.3使用细节 TernaryOperatorDetail.java
int res = a > b ? a++ : --b;
if ( a > b) res = a++;
else res = --b;
//三元运算符细节
public class TernaryOperatorDetail {
//编写一个 main 方法
public static void main(String[] args) {
//表达式 1 和表达式 2 要为可以赋给接收变量的类型
//(或可以自动转换/或者强制转换)
int a = 3;
int b = 8;
int c = a > b ? (int)1. 1 : (int)3.4;//可以的
double d = a > b ? a : b + 3;//可以的,满足 int -> double
}
}
4.6.4课堂练习
案例:实现三个数的最大值 TernaryOperatorExercise.java
public class TernaryOperatorExercise {
//编写一个 main 方法
public static void main(String[] args) {
//案例:实现三个数的最大值
int n1 = 553;
int n2 = 33;
int n3 = 123;
//思路
//1. 先得到 n1 和 n2 中最大数 , 保存到 max1
//2. 然后再 求出 max1 和 n3 中的最大数,保存到 max2
int max1 = n1 > n2 ? n1 : n2;
int max2 = max1 > n3 ? max1 : n3;
System.out.println(“最大数=” + max2);
//使用一条语句实现, 推荐使用上面方法
//老师提示: 后面我们可以使用更好方法, 比如排序
// int max = (n1 > n2 ? n1 : n2) > n3 ?
// (n1 > n2 ? n1 : n2) : n3;
// System.out.println(“最大数=” + max);
//
int abcclass = 10;
int n = 40;
int N = 50;
System.out.println(“n=” + n);//40
System.out.println(“N=” + N);//50
//? abc 和 aBc 是两个不同变量
int abc = 100;
int aBc = 200;
//int a b = 300;
//int a-b=10;
int goto1 = 10;
}
}
4.7 运算符优先级
4.8 标识符的命名规则和规范
4.8. 1判断下面变量名是否正确
hsp hsp12 1hsp h-s // //ok
//ok
//错误, 数字不能开头
错误 , 不能有 -
x h // 错误, 有空格
h$4 // ok
class //错误,class 关键字
int // 错误 ,int 是关键字
double //错误 ,double 是关键字
public //错误 ,public 是关键字
static //错误 ,static 是关键字
goto //错误, goto 是保留字
stu name //ok
4.8.2标识符命名规范[更加专业]
包名:多单词组成时所有字母都小写:aaa.bbb.ccc //比如 com.hsp.crm
类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz [大驼峰] 比如: TankShotGame
变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz [小 驼峰, 简称 驼峰法]
比如: tankShotGame
常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ 比如 :定义一个所得税率 TAX_RATE
后面我们学习到 类,包,接口,等时,我们的命名规范要这样遵守,更加详细的看文档.
4.9 关键字
关键字的定义和特点 (不用背)
定义:被 Java语言赋予了特殊含义,用做专门用途的字符串 (单词)
特点:关键字中所有字母都为小写
import java.util.Scanner;//表示把java.util 下的 Scanner 类导入
public class Input {
//编写一个 main 方法
public static void main(String[] args) {
//演示接受用户的输入
//步骤
//Scanner 类 表示 简单文本扫描器,在java.util 包
//1. 引入/导入 Scanner 类所在的包
//2. 创建 Scanner 对象 , new 创建一个对象,体会
// myScanner 就是 Scanner 类的对象
Scanner myScanner = new Scanner(System.in);
//3. 接收用户输入了, 使用 相关的方法
System.out.println(“请输入名字”);
//当程序执行到 next 方法时,会等待用户输入~~~
String name = myScanner.next(); //接收用户输入字符串
System.out.println(“请输入年龄”);
int age = myScanner.nextInt(); //接收用户输入 int
System.out.println(“请输入薪水”);
double sal = myScanner.nextDouble(); //接收用户输入 double
System.out.println(“人的信息如下:”);
System.out.println(“名字=” + name
}
}
4. 12 进制(程序员的基本功)
4. 12. 1 进制介绍
对于整数,有四种表示方式:
二进制:0, 1 ,满 2 进 1. 以 0b 或 0B 开头。
十进制:0-9 ,满 10 进 1。
八进制:0-7 ,满 8 进 1. 以数字 0 开头表示。
十六进制:0-9 及 A( 10)-F( 15) ,满 16 进 1. 以 0x 或 0X 开头表示。此处的 A-F 不区分大小写。
4. 12.2 举例说明 BinaryTest.java
//演示四种进制
//
public class BinaryTest {
//编写一个 main 方法
public static void main(String[] args) {
//n1 二进制
int n1 = 0b 1010;
//n2 10 进制
int n2 = 1010;
//n3 8 进制
int n3 = 01010;
//n4 16 进制
int n4 = 0X10101;
System.out.println(“n1=” + n1);
System.out.println(“n2=” + n2);
System.out.println(“n3=” + n3);
System.out.println(“n4=” + n4);
System.out.println(0x23A);
}
}
4. 13 进制的图示
第一组:
二进制转十进制
八进制转十进制
十六进制转十进制 第二组:
十进制转二进制
十进制转八进制
十进制转十六进制 第三组
二进制转八进制
二进制转十六进制 第四组
八进制转二进制
十六进制转二进制
15 二进制转换成十进制示例
16 八进制转换成十进制示例
17 十六进制转换成十进制示例
规则:从最低位(右边)开始,将每个位上的数提取出来,乘以 16 的(位数- 1)次方,然后求和。
案例:请将 0x23A 转成十进制的数
0x23A = 10 * 16^0 + 3 * 16 ^ 1 + 2 * 16^2 = 10 + 48 + 512 = 570
课堂练习:请将
0b 110001100 转成 十进制
02456 转成十进制
0xA45 转成十进制
18 十进制转换成二进制
规则:将该数不断除以 2 ,直到商为 0 为止,然后将每步得到的余数倒过来,就是对应的二进制。 案例:请将 34 转成二进制 = 0B00100010
19 十进制转换成八进制
规则:将该数不断除以 8 ,直到商为 0 为止,然后将每步得到的余数倒过来,就是对应的八进制。 案例:请将 131 转成八进制 => 0203
4.20 十进制转换成十六进制
规则:将该数不断除以 16 ,直到商为 0 为止,然后将每步得到的余数倒过来,就是对应的十六进制。
案例:请将 237 转成十六进制 => 0xED
课堂练习:(一定练习,使用计算器/用程序去验证)
123 转成 二进制 => ?
678 转成八进制 => ?
8912 转成十六进制 => ?
4.21 二进制转换成八进制
规则:从低位开始,将二进制数每三位一组,转成对应的八进制数即可。
案例:请将 ob 11010101 转成八进制
ob 11(3)010(2) 101(5) => 0325
4.22 二进制转换成十六进制
规则:从低位开始,将二进制数每四位一组,转成对应的十六进制数即可。
案例:请将 ob 11010101 转成十六进制
ob 1101(D)0101(5) = 0xD5
课堂练习:请将
0b 11100101 转成 八进制
0b 1110010110 转成 十六进制
4.23 八进制转换成二进制
规则:将八进制数每 1 位,转成对应的一个 3 位的二进制数即可。
案例:请将 0237 转成二进制
02(010)3(011)7( 111) = 0b 10011111
4.24 十六进制转换成二进制
规则:将十六进制数每 1 位,转成对应的 4 位的一个二进制数即可。
案例:请将 0x23B 转成二进制
0x2(0010)3(0011)B( 1011) = 0b001000111011
课堂练习:请将
01230 转成 二进制
0xAB29 转成二进制
4.25 位运算的思考题
4.27 原码、反码、补码(重点 难点)
4.28 位运算符
4.28. 1 java 中有 7 个位运算(& 、| 、^ 、~ 、>> 、<<和 >>>)
4.28.2 还有 3 个位运算符 >> 、<< 和 >>> , 运算规则:
逻辑右移也叫无符号右移,运算规则是: 低位溢出,高位补 0
第 5 章 程序控制结构
5. 1 程序流程控制介绍
在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句。
5.3 分支控制 if-else
5.3. 1分支控制 if-else 介绍
让程序有选择的的执行,分支控制有三种
5.3.2单分支
//if 的快速入门
import java.util.Scanner;//导入
public class If01 {
//编写一个 main 方法
public static void main(String[] args) {
//编写一个程序,可以输入人的年龄,如果该同志的年龄大于 18 岁,
//则输出 “你年龄大于 18,要对自己的行为负责,送入监狱”
//
//思路分析
//1. 接收输入的年龄, 应该定义一个 Scanner 对象
//2. 把年龄保存到一个变量 int age
//3. 使用 if 判断,输出对应信息
//应该定义一个 Scanner 对象
Scanner myScanner = new Scanner(System.in);
System.out.println(“请输入年龄”);
//把年龄保存到一个变量 int age
int age = myScanner.nextInt();
//使用 if 判断,输出对应信息
if(age > 18) {
System.out.println(“你年龄大于 18,要对自己的行为负责,送入监狱”);
}
System.out.println(“程序继续…”);
}
}
5.4 双分支
//if-else 的快速入门
import java.util.Scanner;//导入
public class If02 {
//编写一个 main 方法
public static void main(String[] args) {
//编写一个程序,可以输入人的年龄,如果该同志的年龄大于 18 岁,
//则输出 “你年龄大于 18,要对
//自己的行为负责, 送入监狱” 。否则 ,输出"你的年龄不大这次放过你了."
//
//思路分析
//1. 接收输入的年龄, 应该定义一个 Scanner 对象
//2. 把年龄保存到一个变量 int age
//3. 使用 if-else 判断,输出对应信息
//应该定义一个 Scanner 对象
Scanner myScanner = new Scanner(System.in);
System.out.println(“请输入年龄”);
//把年龄保存到一个变量 int age
int age = myScanner.nextInt();
//使用 if-else 判断,输出对应信息
if(age > 18) {
System.out.println(“你年龄大于 18,要对自己的行为负责,送入监狱”);
} else {//双分支
System.out.println(“你的年龄不大这次放过你了”);
}
System.out.println(“程序继续…”);
}
}
5.4. 1双分支
5.4.2单分支和双分支练习题
//IfExercise01.java
【课后自己练】定义两个变量int ,判断二者的和,是否能被 3 又能被 5 整除,打印提示信息
//单分支和双分支的练习
//
public class IfExercise01 {
//编写一个 main 方法
public static void main(String[] args) {
//编写程序,声明2 个 double 型变量并赋值。
//判断第一个数大于 10.0 ,且第 2 个数小于 20.0 ,打印两数之和
//思路分析
double d 1 = 33.5;
double d2 = 2.6;
if(d1 > 10.0 && d2 < 20.0) {
System.out.println(“两个数和=” + (d1 + d2));
}
//【课后自己练】定义两个变量int ,判断二者的和,
//是否能被 3 又能被 5 整除,打印提示信息
//
//思路分析
//1. 定义两个变量 int num1, num2
//2. 定义一个变量 int sum = num1 + num2;
//3. sum % 3 , 5 后 等于 0 说明可以整除
//4. 使用 if - else 来提示对应信息
//走代码
int num1 = 10;
int num2 = 1;
int sum = num1 + num2;
if(sum % 3 == 0 && sum % 5 == 0) {
System.out.println(“和可以被 3 又能被 5 整除”);
} else {
System.out.println(“和不能被 3 和 5 整除…”);
}
//判断一个年份是否是闰年,闰年的条件是符合下面二者之一:
//(1)年份能被 4 整除,但不能被 100 整除;(2)能被 400 整除
//
//思路分析
//1. 定义 int year 保存年
//2. 年份能被 4 整除,但不能被 100 整除,
// => year % 4 == 0 && year % 100 != 0
//3. 能被 400 整除 => year % 400 == 0
//4. 上面的 2 和 3 是 或的关系
//代码实现
int year = 2028;
if( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ) {
System.out.println(year + " 是 闰年");
} else {
System.out.println(year + " 不是 闰年");
}
}
}
5.4.3多分支
多分支的流程图(重要!)
5.4.4多分支
案例演示 1
请大家看个案例[If03.java]:
输入保国同志的芝麻信用分:
如果:
信用分为 100 分时,输出 信用极好;
信用分为(80 ,99]时,输出 信用优秀;
信用分为[60,80]时,输出 信用一般;
其它情况 ,输出 信用 不及格
请从键盘输入保国的芝麻信用分,并加以判断 代码:
//课堂练习
import java.util.Scanner;
public class If03 {
//编写一个 main 方法
public static void main(String[] args) {
/*
输入保国同志的芝麻信用分:
如果:
信用分为 100 分时,输出 信用极好;
信用分为(80 ,99]时,输出 信用优秀;
信用分为[60,80]时,输出 信用一般;
其它情况 ,输出 信用 不及格
请从键盘输入保国的芝麻信用分,并加以判断
假定信用分数为int
*/
Scanner myScanner = new Scanner(System.in);
//接收用户输入
System.out.println(“请输入信用分(1- 100):”);
//请思考:如果小伙伴输入的不是整数,而是hello…
//==>这里我们后面可以使用异常处理机制搞定- 》老师点一下
int grade = myScanner.nextInt();
//先对输入的信用分,进行一个范围的有效判断 1- 100, 否则提示输入错误
if(grade >=1 && grade <= 100) {
//因为有 4 种情况,所以使用多分支
if(grade == 100) {
System.out.println(“信用极好”);
} else if (grade > 80 && grade <= 99) { //信用分为(80 ,99]时,输出 信用优秀;
System.out.println(“信用优秀”);
} else if (grade >= 60 && grade <= 80) {//信用分为[60,80]时,输出 信用一般
System.out.println(“信用一般”);
} else {//其它情况 ,输出 信用 不及格
System.out.println(“信用不及格”);
}
} else {
System.out.println(“信用分需要在 1- 100,请重新输入:)”);
}
}
}
案例演示 2
5.5 嵌套分支
5.5. 1基本介绍
在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分支外面的分支结构称为外 层分支。老师建议: 不要超过 3 层 (可读性不好)
5.5.2基本语法
5.5.3应用案例
参加歌手比赛,如果初赛成绩大于 8.0 进入决赛,否则提示淘汰。并且根据性别提示进入男子组或女子组。【可以
让学员先练习下】, 输入成绩和性别,进行判断和输出信息。[NestedIf.java]
提示: double score; char gender;
接收字符: char gender = scanner.next().charAt(0)
import java.util.Scanner;
public class NestedIf {
//编写一个 main 方法
public static void main(String[] args) {
/*
参加歌手比赛,如果初赛成绩大于 8.0 进入决赛,
否则提示淘汰。并且根据性别提示进入男子组或女子组。
【可以让学员先练习下】, 输入成绩和性别,进行判断和输出信息。
[NestedIf.java]
提示: double score; char gender;
接收字符: char gender = scanner.next().charAt(0)
*/
//思路分析
//1. 创建 Scanner 对象,接收用户输入
//2. 接收 成绩保存到 double score
//3. 使用 if-else 判断 如果初赛成绩大于 8.0 进入决赛,否则提示淘汰
//4. 如果进入到 决赛,再接收 char gender, 使用 if-else 输出信息
//代码实现 => 思路 --> java 代码
Scanner myScanner = new Scanner(System.in);
System.out.println(“请输入该歌手的成绩”);
double score = myScanner.nextDouble();
if( score > 8.0 ) {
System.out.println(“请输入性别”);
char gender = myScanner.next().charAt(0);
if( gender == ‘男’ ) {
System.out.println(“进入男子组”);
} else if(gender == ‘女’) {
System.out.println(“进入女子组”);
} else {
System.out.println(“你的性别有误,不能参加决赛~”);
}
} else {
System.out.println(“sorry ,你被淘汰了~”);
}
}
}
5.5.4应用案例 2, 一定自己做.
5.6 switch 分支结构
5.6. 1基本语法
5.6.2流程图
5.6.3快速入门
案例:Switch01.java
请编写一个程序,该程序可以接收一个字符,比如:a,b,c,d,e,f,g
a 表示星期一,b 表示星期二 …
根据用户的输入显示相应的信息.要求使用 switch 语句完成
代码
import java.util.Scanner;
public class Switch01 {
//编写一个 main 方法
public static void main(String[] args) {
/*
案例:Switch01.java
请编写一个程序,该程序可以接收一个字符,比如:a,b,c,d,e,f,g
a 表示星期一,b 表示星期二 …
根据用户的输入显示相应的信息.要求使用 switch 语句完成
思路分析
*/
Scanner myScanner = new Scanner(System.in);
System.out.println(“请输入一个字符(a-g)”);
char c1 = myScanner.next().charAt(0);//
//在java 中,只要是有值返回,就是一个表达式
switch(c1) {
case ‘a’ :
System.out.println(“今天星期一,猴子穿新衣”);
break;
case ‘b’ :
System.out.println(“今天星期二,猴子当小二”);
break;
case ‘c’ :
System.out.println(“今天星期三,猴子爬雪山…”);
break;
//…
default:
System.out.println(“你输入的字符不正确,没有匹配的”);
}
System.out.println(“退出了 switch ,继续执行程序”);
}
}
5.6.4switch 注意事项和细节讨论
5.6.5switch 课堂练习(学员先做)
SwitchExercise.java
import java.util.Scanner;
public class SwitchExercise {
//编写一个 main 方法
public static void main(String[] args) {
//使用 switch 把小写类型的
//char 型转为大写(键盘输入) 。只转换 a->A, b->B, c, d, e.
//其它的输出 “other”。
//创建 Scanner 对象
// Scanner myScanner = new Scanner(System.in);
// System.out.println(“请输入 a-e”);
// char c1 = myScanner.next().charAt(0);
// switch(c1) {
// case ‘a’ :
// System.out.println(“A”);
// break;
// case ‘b’ :
// System.out.println(“B”);
// break;
// case ‘c’ :
// System.out.println(“C”);
// break;
// case ‘d’ :
// System.out.println(“D”);
// break;
// case ‘e’ :
// System.out.println(“E”);
// break;
// default :
// System.out.println(“你的输入有误~”);
// }
//对学生成绩大于 60 分的,输出"合格" 。低于 60 分的,
//输出"不合格" 。(注:输入的成绩不能大于 100), 提示 成绩/60
//思路分析
//1. 这道题,可以使用 分支来完成, 但是要求使用 switch
//2. 这里我们需要进行一个转换, 编程思路 :
// 如果成绩在 [60, 100] , (int)(成绩/60) = 1
// 如果成绩在 [0,60) , (int)(成绩/60) = 0
//代码实现
double score = 1. 1;
//使用 if-else 保证输入的成绩有有效的 0- 100
//看了当老师的分析和代码演示后, 自己一定要独立完成 (不看老韩代码,也能写)
if( score >= 0 && score <= 100) {
switch ((int)(score / 60)) {
case 0 :
System.out.println(“不合格”);
break;
case 1 :
System.out.println(“合格”);
break;
// default :
// System.out.println(“输入有误”);
}
} else {
System.out.println(“输入的成绩在 0- 100”);
}
//根据用于指定月份,
//打印该月份所属的季节。
//3,4,5 春季 6,7,8 夏季 9, 10, 11 秋季 12, 1, 2 冬季
//[课堂练习, 提示 使用穿透 ]
//
//思路分析
//1. 创建 Scanner 对象, 接收用户输入
//2. 使用 int month 接收
//3. 使用 switch 来匹配 ,使用穿透来完成,比较简洁
Scanner myScanner = new Scanner(System.in);
System.out.println(“输入月份”);
int month = myScanner.nextInt();
switch(month) {
case 3:
case 4:
case 5:
System.out.println(“这是春季”);
break;
case 6:
case 7:
case 8:
System.out.println(“这是夏季”);
break;
case 9:
case 10:
case 11:
System.out.println(“这是秋季”);
break;
case 1:
case 2:
case 12:
System.out.println(“这是冬季”);
break;
default :
System.out.println(“你输入的月份不对(1- 12)”);
}
}
}
5.6.6switch 和 if 的比较
基本介绍:听其名而知其意,就是让你的代码可以循环的执行.
5.7. 1看一个实际需求
请大家看个案例[For01.java]:编写一个程序, 可以打印 10 句 “你好,韩顺平教育!” 。请大家想想怎么做?
5.7.2基本语法
老韩说明
使用for 循环完成前面的题
画出 for 流程图
代码执行, 内存分析法(初学者)图
5.7.4注意事项和细节说明
ForDetail.java
循环条件是返回一个布尔值的表达式
for(;循环判断条件;) 中的初始化和变量迭代可以写到其它地方,但是两边的分号不能省略。
循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,循环变量迭代也可以有多条变量迭代 语句,中间用逗号隔开。
使用内存分析法,老师分析输出下面代码输出什么?
5.7.5 for 循环练习题(学员先做)
ForExercise.java
public class ForExercise {
//编写一个 main 方法
public static void main(String[] args) {
//打印 1~ 100 之间所有是 9 的倍数的整数,统计个数 及 总和.[化繁为简,先死后活]
//老韩的两个编程思想(技巧)
//1. 化繁为简 : 即将复杂的需求,拆解成简单的需求,逐步完成 编程 = 思想 --练习-> 代码
//2. 先死后活 : 先考虑固定的值,然后转成可以灵活变化的值
//
//思路分析
//打印 1~ 100 之间所有是 9 的倍数的整数,统计个数 及 总和
//化繁为简
//(1) 完成 输出 1- 100 的值
//(2) 在输出的过程中,进行过滤,只输出 9 的倍数 i % 9 ==0
//(3) 统计个数 定义一个变量 int count = 0; 当 条件满足时 count++;
//(4) 总和 , 定义一个变量 int sum = 0; 当条件满足时累积 sum += i;
//先死后活
//(1) 为了适应更好的需求,把范围的开始的值和结束的值,做出变量
//(2) 还可以更进一步 9 倍数也做成变量 int t = 9;
int count = 0; //统计 9 的倍数个数 变量
int sum = 0; //总和
int start = 10;
int end = 200;
int t = 5; // 倍数
for(int i = start; i <= end; i++) {
if( i % t == 0) {
System.out.println(“i=” + i);
count++;
sum += i;//累积
}
}
System.out.println(“count=” + count);
System.out.println(“sum=” + sum);
}
}
public class ForExercise02 {
//编写一个 main 方法
public static void main(String[] args) {
//化繁为简
//先死后活
int n = 9;
for( int i = 0; i <= n; i++) {
System.out.println(i + “+” + (n-i) + “=” + n);
}
}
}
5.8 while 循环控制
5.8. 1基本语法
5.8.2while 循环执行流程分析
While01.java
画出流程图
使用 while 循环完成前面的题
//while 循环的案例
//
public class While01 {
//编写一个 main 方法
public static void main(String[] args) {
//输出 10 句 你好,韩顺平教育
int i = 1; //循环变量初始化
while( i <= 10 ) {//循环条件
System.out.println(“你好,韩顺平教育” + i);//执行语句
i++;//循环变量迭代
}
System.out.println(“退出 while ,继续…” + i); // 11
}
}
5.8.3注意事项和细节说明
public class WhileExercise {
//编写一个 main 方法
public static void main(String[] args) {
// 打印 1— 100 之间所有能被 3 整除的数 [使用 while, 老师评讲 ]
// 化繁为简, 先死后活
int i = 1;
int endNum = 100;
while( i <= endNum) {
if( i % 3 == 0) {
System.out.println(“i=” + i);
}
i++;//变量自增
}
// 打印 40—200 之间所有的偶数 [使用 while, 课后练习]
// 化繁为简, 先死后活(利于思考)
//
System.out.println(“========”);
int j = 40; //变量初始化
while ( j <= 200) {
//判断
if( j % 2 == 0) {
System.out.println(“j=” + j);
}
j++;//循环变量的迭代
}
}
}
5.9 do…while 循环控制
5.9. 1基本语法
循环变量初始化;
do{
循环体(语句);
循环变量迭代;
}while(循环条件);
5.9.2老韩说明:
画出流程图
使用 do…while 循环完成前面的题
代码执行内存分析图
5.9.4注意事项和细节说明
public class DoWhileExercise01 {
//编写一个 main 方法
public static void main(String[] args) {
//统计 1—200 之间能被 5 整除但不能被 3 整除的 个数
//化繁为简
//(1) 使用 do-while 输出 1-200
//(2) 过滤 能被 5 整除但不能被 3 整除的数 %
//(3) 统计满足条件的个数 int count = 0;
//先死后活
//(1) 范围的值 1-200 你可以做出变量
//(2) 能被 5 整除但不能被 3 整除的 , 5 和 3 可以改成变量
int i = 1;
int count = 0;//统计满足条件的个数
do {
if( i % 5 == 0 && i % 3 != 0 ) {
System.out.println(“i=” + i);
count++;
}
i++;
}while(i <= 200);
System.out.println(“count=” + count);
}
}
import java.util.Scanner;
public class DoWhileExercise02 {
//编写一个 main 方法
public static void main(String[] args) {
//如果李三不还钱,则老韩将一直使出五连鞭,直到李三说还钱为
//[System.out.println(“老韩问:还钱吗?y/n”)] do…while …
//
//化繁为简
//(1) 不停的问还钱吗?
//(2) 使用 char answer 接收回答, 定义一个 Scanner 对象
//(3) 在 do-while 的 while 判断如果是 y 就不在循环
//一定自己动脑筋…
Scanner myScanner = new Scanner(System.in);
char answer = ’ ';
do {
System.out.println(“老韩使出五连鞭~”);
System.out.println(“老韩问:还钱吗?y/n”);
answer = myScanner.next().charAt(0);
System.out.println(“他的回答是” + answer);
}while(answer != ‘y’);//判断条件很关键
System.out.println(“李三还钱了”);
}
}
将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for ,while ,do …while 均可以作为外层循环和内层循环。 【建议一般使用两层,最多不要超过 3 层, 否则,代码的可读性很差】
实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false 时,才会完全跳出内 层循环,才可结束外层的当次循环,开始下一次的循环[听不懂,走案例]。
设外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n 次。
10.2 多重循环执行步骤分析:
请分析 下面的多重循环执行步骤, 并写出输出 => 韩老师的内存分析法
//双层 for MulFor.java
for(int i = 0; i < 2; i++) { //先思考
for( int j = 0; j < 3; j++) {
System.out.println(“i=” + i + j=" + j);
}
}
10.3 应用实例:
//MulForExercise01.java
import java.util.Scanner;
public class MulForExercise01 {
//编写一个 main 方法
public static void main(String[] args) {
//统计 3 个班成绩情况,每个班有 5 名同学,
//求出各个班的平均分和所有班级的平均分[学生的成绩从键盘输入]。
//统计三个班及格人数,每个班有 5 名同学。
//
//思路分析:
//化繁为简
//(1) 先计算一个班 , 5 个学生的成绩和平均分 , 使用 for
//1. 1 创建 Scanner 对象然后,接收用户输入
//1.2 得到该班级的平均分 , 定义一个 doubel sum 把该班级 5 个学生的成绩累积
//(2) 统计 3 个班(每个班 5 个学生) 平均分
//(3) 所有班级的平均分
//3. 1 定义一个变量,double totalScore 累积所有学生的成绩
//3.2 当多重循环结束后,totalScore / (3 * 5)
//(4) 统计三个班及格人数
//4. 1 定义变量 int passNum = 0; 当有一个学生成绩>=60, passNum++
//4.2 如果 >= 60 passNum++
//(5) 可以优化[效率,可读性, 结构]
//创建 Scanner 对象
Scanner myScanner = new Scanner(System.in);
double totalScore = 0; //累积所有学生的成绩
int passNum = 0;//累积 及格人数
int classNum = 3; //班级个数
int stuNum = 5;//学生个数
for( int i = 1; i <= classNum; i++) {//i 表示班级
double sum = 0; //一个班级的总分
for( int j = 1;j <= stuNum;j++) {//j 表示学生
System.out.println(“请数第”+i+“个班的第”+j+“个学生的成绩”);
double score = myScanner.nextDouble();
//当有一个学生成绩>=60, passNum++
if(score >= 60) {
passNum++;
}
sum += score; //累积
System.out.println(“成绩为” + score);
}
//因为 sum 是 5 个学生的总成绩
System.out.println(“sum=” + sum + " 平均分=" + (sum / stuNum));
//把 sum 累积到 totalScore
totalScore += sum;
}
System.out.println(“三个班总分=”+ totalScore
}
}
public class Stars {
//编写一个 main 方法
public static void main(String[] args) {
/*
*
思路分析
化繁为简
//第 1 层 有 1 个*
//第 2 层 有 2 个*
//第 3 层 有 3 个*
//第 4 层 有 4 个*
//第 5 层 有 5 个*
//第 1 层 有 1 个* 2 * 1 - 1 有 4=(总层数- 1)个空格 *** //第 2 层 有 3 个* 2 * 2 - 1 有 3=(总层数-2)个空格
***** //第 3 层 有 5 个* 2 * 3 - 1 有 2=(总层数-3)个空格
******* //第 4 层 有 7 个* 2 * 4 - 1 有 1=(总层数-4)个空格
********* //第 5 层 有 9 个* 2 * 5 - 1 有 0=(总层数-5)个空格
4. 打印空心的金字塔 [最难的]
*
先死后活
5 层数做成变量 int totalLevel = 5;
//小伙伴 技术到位,就可以很快的把代码写出
*/
int totalLevel = 20; //层数
for(int i = 1; i <= totalLevel; i++) { //i 表示层数
//在输出*之前,还有输出 对应空格 = 总层数- 当前层
for(int k = 1; k <= totalLevel - i; k++ ) {
System.out.print(" ");
}
//控制打印每层的个数
for(int j = 1;j <= 2 * i - 1;j++) {
//当前行的第一个位置是,最后一个位置也是*, 最后一层全部 *
if(j == 1 || j == 2 * i - 1 || i == totalLevel) {
System.out.print(““);
} else { //其他情况输出空格
System.out.print(” ");
}
}
//每打印完一层的后,就换行 println 本身会换行
System.out.println(”");
}
}
}
… …
}
5. 11.4 以 while 使用 break 为例,画出示意图
11.5 快速入门:
Break01.java
11.6 注意事项和细节说明:
11.7 课堂练习题:
BreakExercise.java
public class BreakExercise {
//编写一个 main 方法
public static void main(String[] args) {
//1- 100 以内的数求和,求出 当和 第一次大于 20 的当前数 【for + break】
//思路分析
//1. 循环 1- 100, 求和 sum
//2. 当 sum > 20 时,记录下当前数,然后 break
//3. 在 for 循环外部,定义变量 n , 把当前 i 赋给 n
int sum = 0; //累积和
//注意 i 的作用范围在 for{}
int n = 0;
for(int i = 1; i <= 100; i++) {
sum += i;//累积
if(sum > 20) {
System.out.println(“和>20 时候 当前数 i=” + i);
n = i;
break;
}
}
System.out.println(“当前数=” + n);
}
}
import java.util.Scanner;
public class BreakExercise02 {
//编写一个 main 方法
public static void main(String[] args) {
//实现登录验证,有 3 次机会,如果用户名为"丁真" ,密码"666"提示登录成功,
//否则提示还有几次机会,请使用 for+break 完成
//
// 思路分析
// 1. 创建 Scanner 对象接收用户输入
// 2. 定义 String name ; String passwd; 保存用户名和密码
// 3. 最多循环 3 次[登录 3 次] ,如果 满足条件就提前退出
// 4. 定义一般变量 int chance 记录还有几次登录机会
//
// 代码实现
Scanner myScanner = new Scanner(System.in);
String name = “”;
String passwd = “”;
int chance = 3; //登录一次 ,就减少一次
for( int i = 1; i <= 3; i++) {//3 次登录机会
System.out.println(“请输入名字”);
name = myScanner.next();
System.out.println(“请输入密码”);
passwd = myScanner.next();
//比较输入的名字和密码是否正确
//补充说明字符串 的内容 比较 使用的 方法 equals
if(“丁真”.equals(name) && “666”.equals(passwd)) {
System.out.println(“恭喜你,登录成功~”);
break;
}
//登录的机会就减少一次
chance–;
System.out.println(“你还有” + chance + “次登录机会”);
}
}
}
5. 12 跳转控制语句-continue
5. 12. 1 基本介绍:
… …
}
5. 12.3 以 while 使用 continue 为例,画出示意图
12.4 快速入门案例
Continue01.java
12.5 细节案例分析和说明: ContinueDetail.java
label 1:
for(int j = 0; j < 4; j++){
label2:
for(int i = 0; i < 10; i++){
if(i == 2){
//看看分别输出什么值,并分析
//continue ;
//continue label2;
continue label 1;
}
System.out.println("i = " + i);
}
}
果 return 写在 main 方法,退出程序…Return01.java
第 6 章 数组、排序和查找
6. 1 为什么需要数组
一个养鸡场有 6 只鸡,它们的体重分别是 3kg,5kg, 1kg,3.4kg,2kg,50kg 。请问这六只鸡的总体重是多少?平 均体重是多少? 请你编一个程序。 Array01.java
思路:
定义 6 个变量 , 加起来 总体重, 求出平均体重. 引出 -> 数组
6. 1. 1数组介绍
数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型。
即:数(数据)组(一组)就是一组数据
6. 1.2 数组快速入门
Array01.java
比如,我们可以用数组来解决上一个问题。 体验
//数组的引出
//
public class Array01 {
//编写一个 main 方法
public static void main(String[] args) {
/*
它们的体重分别是 3kg,5kg, 1kg,3.4kg,2kg,50kg 。
请问这六只鸡的总体重是多少?平均体重是多少?
思路分析
// double hen1 = 3;
// double hen2 = 5;
// double hen3 = 1;
// double hen4 = 3.4;
// double hen5 = 2;
// double hen6 = 50;
// double totalWeight = hen1 + hen2 + hen3 + hen4 + hen5 + hen6;
// double avgWeight = totalWeight / 6;
// System.out.println(“总体重=” + totalWeight
// + “平均体重=” + avgWeight);
//比如,我们可以用数组来解决上一个问题 => 体验
//
//定义一个数组
//老韩解读
//1. double[] 表示 是 double 类型的数组, 数组名 hens
//2. {3, 5, 1, 3.4, 2, 50} 表示数组的值/元素,依次表示数组的
// 第几个元素
//
double[] hens = {3, 5, 1, 3.4, 2, 50, 7.8, 88.8, 1. 1,5.6, 100};
//遍历数组得到数组的所有元素的和, 使用for
//老韩解读
//1. 我们可以通过 hens[下标] 来访问数组的元素
// 下标是从 0 开始编号的比如第一个元素就是 hens[0]
// 第 2 个元素就是 hens[ 1] , 依次类推
//2. 通过 for 就可以循环的访问 数组的元素/值
//3. 使用一个变量 totalWeight 将各个元素累积
System.out.println(“=使用数组解决=”);
//老师提示: 可以通过 数组名.length 得到数组的大小/长度
//System.out.println(“数组的长度=” + hens.length);
double totalWeight = 0;
for( int i = 0; i < hens.length; i++) {
//System.out.println(“第” + (i+1) + “个元素的值=” + hens[i]);
totalWeight += hens[i];
}
System.out.println(“总体重=” + totalWeight
}
}
6.2 数组的使用
import java.util.Scanner;
public class Array02 {
//编写一个 main 方法
public static void main(String[] args) {
//演示 数据类型 数组名[]=new 数据类型[大小]
//循环输入 5 个成绩,保存到 double 数组,并输出
//步骤
//1. 创建一个 double 数组,大小 5
//(1) 第一种动态分配方式
//double scores[] = new double[5];
//(2) 第 2 种动态分配方式, 先声明数组,再 new 分配空间
double scores[] ; //声明数组, 这时 scores 是 null
scores = new double[5]; // 分配内存空间,可以存放数据
//2. 循环输入
// scores.length 表示数组的大小/长度
//
Scanner myScanner = new Scanner(System.in);
for( int i = 0; i < scores.length; i++) {
System.out.println(“请输入第”+ (i+1) +“个元素的值”);
scores[i] = myScanner.nextDouble();
}
//输出,遍历数组
System.out.println(“数组的元素/值的情况如下:=”);
for( int i = 0; i < scores.length; i++) {
System.out.println(“第”+ (i+1) +“个元素的值=” + scores[i]);
}
}
}
6.2. 1使用方式 2-动态初始化
先声明数组
语法:数据类型 数组名[]; 也可以 数据类型[] 数组名;
int a[]; 或者 int[] a;
创建数组
语法: 数组名=new 数据类型[大小];
a=new int[10];
案例演示【前面修改即可】
6.2.2使用方式 3-静态初始化
6.3 数组使用注意事项和细节
int [] arr=new int[5]; 则有效下标为 0-4
7) 数组属引用类型,数组型数据是对象(object)
代码:
public class ArrayDetail {
//编写一个 main 方法
public static void main(String[] args) {
//1. 数组是多个相同类型数据的组合,实现对这些数据的统一管理
//int[] arr1 = { 1, 2, 3, 60,“hello”};//String ->int
double[] arr2 = { 1. 1, 2.2, 3.3, 60.6, 100};//int ->double
//2. 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用
String[] arr3 = {“北京”,“jack”,“milan”};
//3. 数组创建后,如果没有赋值,有默认值
//int 0 ,short 0, byte 0, long 0,
//float 0.0,double 0.0 ,char \u0000,
//boolean false ,String null
//
short[] arr4 = new short[3];
System.out.println(“=数组 arr4=”);
for(int i = 0; i < arr4.length; i++) {
System.out.println(arr4[i]);
}
//6. 数组下标必须在指定范围内使用,否则报:下标越界异常,比如
//int [] arr=new int[5]; 则有效下标为 0-4
//即数组的下标/索引 最小 0 最大 数组长度- 1(4)
int [] arr = new int[5];
//System.out.println(arr[5]);//数组越界
}
}
6.4 数组应用案例
public class ArrayExercise01 {
//编写一个 main 方法
public static void main(String[] args) {
/*
创建一个 char 类型的 26 个元素的数组,分别 放置’A’-‘Z’。
使用for 循环访问所有元素并打印出来。
提示:char 类型数据运算 ‘A’+ 1 -> ‘B’
思路分析
//循环输出
System.out.println(“=chars 数组=”);
for( int i = 0; i < chars.length; i++) {//循环 26 次
System.out.print(chars[i] + " ");
}
}
}
public class ArrayExercise02 {
//编写一个 main 方法
public static void main(String[] args) {
//请求出一个数组 int[]的最大值 {4,- 1,9, 10,23} ,并得到对应的下标
//老韩思路分析
//1. 定义一个 int 数组 int[] arr = {4,- 1,9, 10,23};
//2. 假定 max = arr[0] 是最大值 , maxIndex=0;
//3. 从下标 1 开始遍历 arr , 如果 max < 当前元素,说明 max 不是真正的
// 最大值, 我们就 max=当前元素; maxIndex=当前元素下标
//4. 当我们遍历这个数组 arr 后 , max 就是真正的最大值,maxIndex 最大值
// 对应的下标
int[] arr = {4,- 1,9, 10,23};
int max = arr[0];//假定第一个元素就是最大值
int maxIndex = 0; //
for(int i = 1; i < arr.length; i++) {//从下标 1 开始遍历 arr
if(max < arr[i]) {//如果 max < 当前元素
max = arr[i]; //把 max 设置成 当前元素
maxIndex = i;
}
}
//当我们遍历这个数组 arr 后 , max 就是真正的最大值,maxIndex 最大值下标
System.out.println(“max=” + max + " maxIndex=" + maxIndex);
}
}
6.6 数组拷贝
编写代码 实现数组拷贝(内容复制)ArrayCopy.java
将 int[] arr1 = { 10,20,30}; 拷贝到 arr2 数组, 要求数据空间是独立的.
public class ArrayCopy {
//编写一个 main 方法
public static void main(String[] args) {
//将 int[] arr1 = { 10,20,30}; 拷贝到 arr2 数组,
//要求数据空间是独立的.
int[] arr1 = { 10,20,30};
//创建一个新的数组 arr2,开辟新的数据空间
//大小 arr1.length;
int[] arr2 = new int[arr1.length];
//遍历 arr1 ,把每个元素拷贝到 arr2 对应的元素位置
for(int i = 0; i < arr1.length; i++) {
arr2[i] = arr1[i];
}
//老师修改 arr2 , 不会对 arr1 有影响.
arr2[0] = 100;
//输出 arr1
System.out.println(“arr1 的元素”);
for(int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);//10,20,30
}
//
System.out.println(“arr2 的元素”);
for(int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);//
}
}
}
6.7 数组反转
要求:把数组的元素内容反转。 ArrayReverse.java
arr { 11,22,33,44,55,66} {66, 55,44,33,22, 11}
//思考 2min
方式 1 :通过找规律反转 【思路分析】
public class ArrayReverse {
//编写一个 main 方法
public static void main(String[] args) {
//定义数组
int[] arr = { 11, 22, 33, 44, 55, 66};
//老韩思路
//规律
//1. 把 arr[0] 和 arr[5] 进行交换 {66,22,33,44,55, 11}
//2. 把 arr[ 1] 和 arr[4] 进行交换 {66,55,33,44,22, 11}
//3. 把 arr[2] 和 arr[3] 进行交换 {66,55,44,33,22, 11}
//4. 一共要交换 3 次 = arr.length / 2
//5. 每次交换时,对应的下标 是 arr[i] 和 arr[arr.length - 1 -i]
//代码
//优化
int temp = 0;
int len = arr.length; //计算数组的长度
for( int i = 0; i < len / 2; i++) {
temp = arr[len - 1 - i];//保存
arr[len - 1 - i] = arr[i];
arr[i] = temp;
}
System.out.println(“=翻转后数组=”);
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + “\t”);//66,55,44,33,22, 11
}
}
}
方式 2 :使用逆序赋值方式 【思路分析, 学员自己完成】 ArrayReverse02.java
public class ArrayReverse02 {
//编写一个 main 方法
public static void main(String[] args) {
//定义数组
int[] arr = { 11, 22, 33, 44, 55, 66};
//使用逆序赋值方式
//老韩思路
//1. 先创建一个新的数组 arr2 ,大小 arr.length
//2. 逆序遍历 arr ,将 每个元素拷贝到 arr2 的元素中(顺序拷贝)
//3. 建议增加一个循环变量 j -> 0 -> 5
int[] arr2 = new int[arr.length];
//逆序遍历 arr
for(int i = arr.length - 1, j = 0; i >= 0; i–, j++) {
arr2[j] = arr[i];
}
//4. 当 for 循环结束,arr2 就是一个逆序的数组 {66, 55, 44,33, 22, 11}
//5. 让 arr 指向 arr2 数据空间, 此时 arr 原来的数据空间就没有变量引用
// 会被当做垃圾,销毁
arr = arr2;
System.out.println(“arr 的元素情况=”);
//6. 输出 arr 看看
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + “\t”);
}
}
}
6.8 数组添加/扩容
要求:实现动态的给数组添加元素效果,实现对数组扩容。ArrayAdd.java
原始数组使用静态分配 int[] arr = { 1,2,3}
增加的元素 4 ,直接放在数组的最后 arr = { 1,2,3,4}
用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n ArrayAdd02.java
2min->试试 2min 思考- 》试试
代码
import java.util.Scanner;
public class ArrayAdd02 {
//编写一个 main 方法
public static void main(String[] args) {
/*
要求:实现动态的给数组添加元素效果,实现对数组扩容。ArrayAdd.java
1.原始数组使用静态分配 int[] arr = { 1,2,3}
2.增加的元素 4 ,直接放在数组的最后 arr = { 1,2,3,4}
3.用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n
思路分析
Scanner myScanner = new Scanner(System.in);
//初始化数组
int[] arr = { 1,2,3};
do {
int[] arrNew = new int[arr.length + 1];
//遍历 arr 数组,依次将 arr 的元素拷贝到 arrNew 数组
for(int i = 0; i < arr.length; i++) {
arrNew[i] = arr[i];
}
System.out.println(“请输入你要添加的元素”);
int addNum = myScanner.nextInt();
//把 addNum 赋给 arrNew 最后一个元素
arrNew[arrNew.length - 1] = addNum;
//让 arr 指向 arrNew,
arr = arrNew;
//输出 arr 看看效果
System.out.println(“arr 扩容后元素情况”);
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + “\t”);
}
//问用户是否继续
System.out.println(“是否继续添加 y/n”);
char key = myScanner.next().charAt(0);
if( key == ‘n’) { //如果输入 n ,就结束
break;
}
}while(true);
System.out.println(“你退出了添加…”);
}
}
课后练习题: ArrayReduce.java
有一个数组 { 1 , 2 , 3 , 4 , 5} , 可以将该数组进行缩减,提示用户是否继续缩减,每次缩减最后那个元素。当只剩 下最后一个元素,提示,不能再缩减。
6.9 排序的介绍
排序是将多个数据,依指定的顺序进行排列的过程。
排序的分类:
6.9. 1内部排序:
指将需要处理的所有数据都加载到内部存储器中进行排序。包括(交换式排序法、选择
式排序法和插入式排序法);
6.9.2外部排序法:
数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法和直接合并排序法)。
6. 10 冒泡排序法
冒泡排序 (Bubble Sorting) 的基本思想是:通过对待排序序列从后向前 (从下标较大的元素开始) ,依次比较相邻元素
的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。
冒泡排序法案例:
BubbleSort.java
下面我们举一个具体的案例来说明冒泡法。我们将五个无序:24,69,80,57, 13 使用冒泡排序法将其排成一个从小到大的有
序数列。
思路->走代码, 你可以自己完整的分析冒泡的执行流程,并可以不看老师代码,也可以写出代码.
代码
public class BubbleSort {
//编写一个 main 方法
public static void main(String[] args) {
//老韩 化繁为简,先死后活
//
//
/*
数组 [24,69,80,57, 13]
第 1 轮排序: 目标把最大数放在最后
第 1 次比较[24,69,80,57, 13]
第 2 次比较[24,69,80,57, 13]
第 3 次比较[24,69,57,80, 13]
第 4 次比较[24,69,57, 13,80]
*/
int[] arr = {24, 69, 80, 57, 13, - 1, 30, 200, - 110};
int temp = 0; //用于辅助交换的变量
//将多轮排序使用外层循环包括起来即可
//先死后活 =》 4 就是 arr.length - 1
for( int i = 0; i < arr.length - 1; i++) {//外层循环是 4 次
for( int j = 0; j < arr.length - 1 - i; j++) {//4 次比较-3 次-2 次- 1 次
//如果前面的数>后面的数,就交换
if(arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println(“\n第"+(i+1)+"轮”);
for(int j = 0; j < arr.length; j++) {
System.out.print(arr[j] + “\t”);
}
}
// for( int j = 0; j < 4;j++) {//4 次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }
// System.out.println(“第 1 轮”);
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + “\t”);
// }
// /*
// 第 2 轮排序: 目标把第二大数放在倒数第二位置
// 第 1 次比较[24,69,57, 13,80]
// 第 2 次比较[24,57,69, 13,80]
// 第 3 次比较[24,57, 13,69,80]
// */
// for( int j = 0; j < 3;j++) {//3 次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }
// System.out.println(“\n第 2 轮”);
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + “\t”);
// }
// 第 3 轮排序: 目标把第 3 大数放在倒数第 3 位置
// 第 1 次比较[24,57, 13,69,80]
// 第 2 次比较[24, 13,57,69,80]
// for( int j = 0; j < 2;j++) {//2 次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }
// System.out.println(“\n第 3 轮”);
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + “\t”);
// }
// /*
// 第 4 轮排序: 目标把第 4 大数放在倒数第 4 位置
// 第 1 次比较[13,24,57,69,80]
// */
// for( int j = 0; j < 1;j++) {//1 次比较
// //如果前面的数>后面的数,就交换
// if(arr[j] > arr[j + 1]) {
// temp = arr[j];
// arr[j] = arr[j+1];
// arr[j+1] = temp;
// }
// }
// System.out.println(“\n第 4 轮”);
// for(int j = 0; j < arr.length; j++) {
// System.out.print(arr[j] + “\t”);
// }
}
}
12 查找
import java.util.Scanner;
public class SeqSearch {
//编写一个 main 方法
public static void main(String[] args) {
/*
有一个数列: 白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王猜数游戏:
从键盘中任意输入一个名称,判断数列中是否包含此名称【顺序查找】
要求: 如果找到了,就提示找到,并给出下标值
思路分析
//定义一个字符串数组
String[] names = {“白眉鹰王”, “金毛狮王”, “紫衫龙王”, “青翼蝠王”};
Scanner myScanner = new Scanner(System.in);
System.out.println(“请输入名字”);
String findName = myScanner.next();
//遍历数组,逐一比较,如果有,则提示信息,并退出
//这里老师给大家一个编程思想/技巧, 一个经典的方法
int index = -1;
for(int i = 0; i < names.length; i++) {
//比较 字符串比较 equals, 如果要找到名字就是当前元素
if(findName.equals(names[i])) {
System.out.println("恭喜你找到 " + findName);
System.out.println("下标为= " + i);
//把 i 保存到 index
index = i;
break;//退出
}
}
if(index == - 1) { //没有找到
System.out.println("sorry ,没有找到 " + findName);
}
}
}
13 多维数组-二维数组
多维数组我们只介绍二维数组。
二维数组的应用场景
比如我们开发一个五子棋游戏,棋盘就是需要二维数组来表示。如图:
14 二维数组的使用
代码
public class TwoDimensionalArray01 {
//编写一个 main 方法
public static void main(String[] args) {
/*
请用二维数组输出如下图形
0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0
*/
//什么是二维数组:
//老韩解读
//1. 从定义形式上看 int[][]
//2. 可以这样理解,原来的一维数组的每个元素是一维数组, 就构成二维数组
int[][] arr = { {0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0},
{0,2, 0, 3, 0, 0},
{0, 0, 0, 0, 0, 0} };
//关于二维数组的关键概念
//(1)
System.out.println(“二维数组的元素个数=” + arr.length);
//(2) 二维数组的每个元素是一维数组, 所以如果需要得到每个一维数组的值
// 还需要再次遍历
//(3) 如果我们要访问第 (i+1)个一维数组的第j+1 个值 arr[i][j];
// 举例 访问 3, =》 他是第 3 个一维数组的第 4 个值 arr[2][3]
System.out.println(“第 3 个一维数组的第 4 个值=” + arr[2][3]); //3
//输出二维图形
for(int i = 0; i < arr.length; i++) {//遍历二维数组的每个元素
//遍历二维数组的每个元素(数组)
//老韩解读
//1. arr[i] 表示 二维数组的第 i+1 个元素 比如 arr[0] :二维数组的第一个元素
//2. arr[i].length 得到 对应的 每个一维数组的长度
for(int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " "); //输出了一维数组
}
System.out.println();//换行
}
}
}
6. 14.2 使用方式 1: 动态初始化
TwoDimensionalArray02.java
语法: 类型[][] 数组名=new 类型[大小][大小]
比如: int a[][]=new int[2][3]
使用演示
二维数组在内存的存在形式(!!画图) 代码
public class TwoDimensionalArray02 {
//编写一个 main 方法
public static void main(String[] args) {
//int arr[][] = new int[2][3];
int arr[][]; //声明二维数组
arr = new int[2][3];//再开空间
arr[ 1][1] = 8;
//遍历 arr 数组
for(int i = 0; i < arr.length; i++) {
for(int j = 0;j < arr[i].length; j++) {//对每个一维数组遍历
System.out.print(arr[i][j] +" ");
}
System.out.println();//换行
}
}
}
代码
public class TwoDimensionalArray03 {
//编写一个 main 方法
public static void main(String[] args) {
/*
看一个需求:动态创建下面二维数组,并输出
i = 0: 1
i = 1: 2 2
i = 2: 3 3 3
一个有三个一维数组, 每个一维数组的元素是不一样的
*/
//创建 二维数组,一个有 3 个一维数组,但是每个一维数组还没有开数据空间
int[][] arr = new int[3][];
for(int i = 0; i < arr.length; i++) {//遍历 arr 每个一维数组
//给每个一维数组开空间 new
//如果没有给一维数组 new ,那么 arr[i]就是 null
arr[i] = new int[i + 1];
//遍历一维数组,并给一维数组的每个元素赋值
for(int j = 0; j < arr[i].length; j++) {
arr[i][j] = i + 1;//赋值
}
}
System.out.println(“=arr 元素=”);
//遍历 arr 输出
for(int i = 0; i < arr.length; i++) {
//输出 arr 的每个一维数组
for(int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();//换行
}
}
}
比如:
int[][] arr = {{1, 1, 1}, {8,8,9}, { 100}};
解读
定义了一个二维数组 arr
arr 有三个元素(每个元素都是一维数组)
第一个一维数组有 3 个元素 , 第二个一维数组有 3 个元素, 第三个一维数组有 1 个元素
14.6 案例:
TwoDimensionalArray05.java
int arr[][]={{4,6}, { 1,4,5,7}, {-2}}; 遍历该二维数组,并得到和
public class TwoDimensionalArray05 {
//编写一个 main 方法
public static void main(String[] args) {
/*
int arr[][]={{4,6}, { 1,4,5,7}, {-2}}; 遍历该二维数组,并得到和
思路
}
}
System.out.println(“sum=” + sum);
}
}
代码
public class YangHui {
//编写一个 main 方法
public static void main(String[] args) {
/*
使用二维数组打印一个 10 行杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
规律
1.第一行有 1 个元素, 第 n 行有 n 个元素
2. 每一行的第一个元素和最后一个元素都是 1
3. 从第三行开始, 对于非第一个元素和最后一个元素的元素的值. arr[i][j] arr[i][j] = arr[i- 1][j] + arr[i- 1][j- 1]; //必须找到这个规律
*/
int[][] yangHui = new int[12][];
for(int i = 0; i < yangHui.length; i++) {//遍历 yangHui 的每个元素
//给每个一维数组(行) 开空间
yangHui[i] = new int[i+1];
//给每个一维数组(行) 赋值
for(int j = 0; j < yangHui[i].length; j++){
//每一行的第一个元素和最后一个元素都是 1
if(j == 0 || j == yangHui[i].length - 1) {
yangHui[i][j] = 1;
} else {//中间的元素
yangHui[i][j] = yangHui[i- 1][j] + yangHui[i- 1][j- 1];
}
}
}
//输出杨辉三角
for(int i = 0; i < yangHui.length; i++) {
for(int j = 0;j < yangHui[i].length; j++) {//遍历输出该行
System.out.print(yangHui[i][j] + “\t”);
}
System.out.println();//换行.
}
}
}
一维数组的声明方式有: int[] x 或者 int x[]
二维数组的声明方式有:
int[][] y 或者 int[] y [] 或者 int y [][]
二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同。比如: map[][] 是
一个二维数组
int map [][] = {{1,2}, {3,4,5}}
由 map[0] 是一个含有两个元素的一维数组 ,map[ 1] 是一个含有三个元素的一维数组构成,我们也称为列数不等
的二维数组
17 二维数组课堂练习
18 本章作业
4 题的分析示意图:
第 7 章 面向对象编程(基础部分)
7. 1 类与对象
7. 1. 1看一个养猫猫问题
张老太养了两只猫猫:一只名字叫小白,今年 3 岁, 白色。还有一只叫小花,今年 100 岁,花色。请编写一个程序,当用户 输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示 张老太没有这只猫猫。
7. 1.2使用现有技术解决 Object01.java
public class Object01 {
//编写一个 main 方法
public static void main(String[] args) {
/*
张老太养了两只猫猫:一只名字叫小白,今年 3 岁, 白色。
还有一只叫小花,今年 100 岁,花色。请编写一个程序,当用户输入小猫的名字时,
就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,
则显示 张老太没有这只猫猫。
*/
//单独变量来解决 => 不利于数据的管理(你把一只猫的信息拆解)
//第 1 只猫信息
// String cat 1Name = “小白”;
// int cat 1Age = 3;
// String cat 1Color = “白色”;
// //第 2 只猫信息
// String cat2Name = “小花”;
// int cat2Age = 100;
// String cat2Color = “花色”;
//数组 ===>(1)数据类型体现不出来(2) 只能通过[下标]获取信息,造成变量名字和内容
// 的对应关系不明确(3) 不能体现猫的行为
//第 1 只猫信息
// String[] cat 1 = {“小白”, “3”, “白色”};
// String[] cat2 = {“小花”, “100”, “花色”};
//使用OOP 面向对象解决
//实例化一只猫[创建一只猫对象]
//老韩解读
//1. new Cat() 创建一只猫(猫对象)
//2. Cat cat 1 = new Cat(); 把创建的猫赋给 cat 1
//3. cat 1 就是一个对象
Cat cat 1 = new Cat();
cat1.name = “小白”;
cat 1.age = 3;
cat 1.color = “白色”;
cat 1.weight = 10;
//创建了第二只猫,并赋给 cat2
//cat2 也是一个对象(猫对象)
Cat cat2 = new Cat();
cat2.name = “小花”;
cat2.age = 100;
cat2.color = “花色”;
cat2.weight = 20;
//怎么访问对象的属性呢
System.out.println(“第 1 只猫信息” + cat 1.name
System.out.println(“第 2 只猫信息” + cat2.name
//使用面向对象的方式来解决养猫问题
//
//定义一个猫类 Cat -> 自定义的数据类型
class Cat {
//属性/成员变量
String name; //名字
int age; //年龄
String color; //颜色
//double weight; //体重
//行为
}
1.4 一个程序就是一个世界,有很多事物(对象[属性, 行为])
1.5类与对象的关系示意图
1.6类与对象的关系示意图
1.7快速入门-面向对象的方式解决养猫问题
Object01.java -> 看前面的代码
1.8类和对象的区别和联系
通过上面的案例和讲解我们可以看出:
1.9对象在内存中存在形式(重要的)必须搞清楚。
public class Object02 {
//编写一个 main 方法
public static void main(String[] args) {
}
}
class Car {
String name;//属性, 成员变量, 字段 field
double price;
String color;
String[] master;//属性可以是基本数据类型,也可以是引用类型(对象,数组)
}
public class PropertiesDetail {
//编写一个 main 方法
public static void main(String[] args) {
//创建 Person 对象
//p1 是对象名(对象引用)
//new Person() 创建的对象空间(数据) 才是真正的对象
Person p1 = new Person();
//对象的属性默认值,遵守数组规则:
//int 0 ,short 0, byte 0, long 0, float 0.0,double 0.0 ,char \u0000 ,boolean false ,String null
System.out.println(“\n 当前这个人的信息”);
System.out.println(“age=” + p1.age + " name="
class Person {
//四个属性
int age;
String name;
double sal;
boolean isPass;
}
Person p = new Person();
p.name = “jack”;
p.age = 10
先加载 Person类信息(属性和方法信息, 只会加载一次)
在堆中分配空间, 进行默认初始化(看规则)
把地址赋给 p , p 就指向对象
进行指定初始化, 比如 p.name =”jack” p.age = 10
看一个练习题,并分析画出内存布局图,进行分析
7.2 成员方法
7.2. 1基本介绍
在某些情况下,我们要需要定义成员方法(简称方法) 。比如人类: 除了有一些属性外( 年龄,姓名…),我们人类还有一 些行为比如:可以说话、跑步…,通过学习,还可以做算术题。这时就要用成员方法才能完成。现在要求对 Person类完善。
7.2.2成员方法快速入门
Method01.java
public class Method01 {
//编写一个 main 方法
public static void main(String[] args) {
//方法使用
//1. 方法写好后,如果不去调用(使用) ,不会输出
//2. 先创建对象 ,然后调用方法即可
Person p1 = new Person();
p1.speak(); //调用方法
p1.cal01(); //调用 cal01 方法
p1.cal02(5); //调用 cal02 方法,同时给 n = 5
p1.cal02(10); //调用 cal02 方法,同时给 n = 10
//调用 getSum 方法,同时 num1= 10, num2=20
//把 方法 getSum 返回的值,赋给 变量 returnRes
int returnRes = p1.getSum( 10, 20);
System.out.println(“getSum 方法返回的值=” + returnRes);
}
}
class Person {
String name;
int age;
//方法(成员方法)
//添加 speak 成员方法,输出 “我是一个好人”
//老韩解读
//1. public 表示方法是公开
//2. void : 表示方法没有返回值
//3. speak() : speak 是方法名, () 形参列表
//4. {} 方法体,可以写我们要执行的代码
//5. System.out.println(“我是一个好人”); 表示我们的方法就是输出一句话
public void speak() {
System.out.println(“我是一个好人”);
}
//添加 cal01 成员方法,可以计算从 1+…+ 1000 的结果
public void cal01() {
//循环完成
int res = 0;
for(int i = 1; i <= 1000; i++) {
res += i;
}
System.out.println(“cal01 方法 计算结果=” + res);
}
//添加 cal02 成员方法,该方法可以接收一个数 n ,计算从 1+…+n 的结果
//老韩解读
//1. (int n) 形参列表, 表示当前有一个形参 n, 可以接收用户输入
public void cal02(int n) {
//循环完成
int res = 0;
for(int i = 1; i <= n; i++) {
res += i;
}
System.out.println(“cal02 方法 计算结果=” + res);
}
//添加 getSum 成员方法,可以计算两个数的和
//老韩解读
//1. public 表示方法是公开的
//2. int :表示方法执行后,返回一个 int 值
//3. getSum 方法名
//4. (int num1, int num2) 形参列表,2 个形参,可以接收用户传入的两个数
//5. return res; 表示把 res 的值, 返回
public int getSum(int num1, int num2) {
int res = num1 + num2;
return res;
}
}
7.2.3方法的调用机制原理:(重要!-示意图!!!)
提示:画出程序执行过程[getSum]+说明
7.2.4为什么需要成员方法
Method02.java
看一个需求:
请遍历一个数组 , 输出数组的各个元素值。
解决思路 1 ,传统的方法,就是使用单个 for 循环,将数组输出,大家看看问题是什么?
解决思路 2: 定义一个类 MyTools ,然后写一个成员方法,调用方法实现,看看效果又如何。
代码
public class Method02 {
//编写一个 main 方法
public static void main(String[] args) {
//请遍历一个数组 , 输出数组的各个元素值
int [][] map = {{0,0, 1}, { 1, 1, 1}, { 1, 1,3}};
//使用方法完成输出, 创建 MyTools 对象
MyTools tool = new MyTools();
//遍历map 数组
//传统的解决方式就是直接遍历
// for(int i = 0; i < map.length; i++) {
// for(int j = 0; j < map[i].length; j++) {
// System.out.print(map[i][j] + “\t”);
// }
// System.out.println();
// }
//使用方法
tool.printArr(map);
//…
//
//要求再次遍历map 数组
// for(int i = 0; i < map.length; i++) {
// for(int j = 0; j < map[i].length; j++) {
// System.out.print(map[i][j] + “\t”);
// }
// System.out.println();
// }
tool.printArr(map);
//…再次遍历
//
// for(int i = 0; i < map.length; i++) {
// for(int j = 0; j < map[i].length; j++) {
// System.out.print(map[i][j] + “\t”);
// }
// System.out.println();
// }
tool.printArr(map);
}
}
//把输出的功能,写到一个类的方法中,然后调用该方法即可
class MyTools {
//方法,接收一个二维数组
public void printArr(int[][] map) {
System.out.println(“=======”);
//对传入的map 数组进行遍历输出
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j] + “_”);
}
System.out.println();
}
}
}
7.2.5成员方法的好处
访问修饰符 返回数据类型 方法名 (形参列表… ) {//方法体
语句;
return 返回值;
}
形参列表:表示成员方法输入 cal(int n) , getSum(int num1, int num2)
返回数据类型:表示成员方法输出, void 表示没有返回值
方法主体:表示为了实现某一功能代码块
return 语句不是必须的。
老韩提示: 结合前面的题示意图, 来理解
7.2.7注意事项和使用细节
MethodDetail.java
public class MethodDetail {
public static void main(String[] args) {
AA a = new AA();
int[] res = a.getSumAndSub(1, 4);
System.out.println(“和=” + res[0]);
System.out.println(“差=” + res[ 1]);
//细节: 调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型 的参数
byte b 1 = 1;
byte b2 = 2;
a.getSumAndSub(b1, b2);//byte -> int
//a.getSumAndSub(1. 1, 1.8);//double ->int(×)
//细节: 实参和形参的类型要一致或兼容、个数、顺序必须一致
//a.getSumAndSub(100);//× 个数不一致
a.f3(“tom”, 10); //ok
//a.f3( 100, “jack”); // 实际参数和形式参数顺序不对
}
}
class AA {
//细节: 方法不能嵌套定义
public void f4() {
//错误
// public void f5() {
// }
}
public void f3(String str, int n) {
}
//1. 一个方法最多有一个返回值 [思考,如何返回多个结果 返回数组 ]
public int[] getSumAndSub(int n1, int n2) {
int[] resArr = new int[2]; //
resArr[0] = n1 + n2;
resArr[ 1] = n1 - n2;
return resArr;
}
//2. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
// 具体看 getSumAndSub
//
//3. 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值;
// 而且要求返回值类型必须和 return 的值类型一致或兼容
public double f1() {
double d 1 = 1. 1 * 3;
int n = 100;
return n; // int ->double
//return d 1; //ok? double -> int
}
//如果方法是 void ,则方法体中可以没有 return 语句,或者 只写 return ;
//老韩提示:在实际工作中,我们的方法都是为了完成某个功能,所以方法名要有一定含义
// ,最好是见名知意
public void f2() {
System.out.println(“hello1”);
System.out.println(“hello1”);
System.out.println(“hello1”);
int n = 10;
//return ;
}
}
访问修饰符 (作用是控制 方法使用的范围)
如果不写默认访问,[有四种: public, protected, 默认, private], 具体在后面说
返回数据类型
public class MethodDetail02 {
//编写一个 main 方法
public static void main(String[] args) {
A a = new A();
//a.sayOk();
a.m1();
}
}
class A {
//同一个类中的方法调用:直接调用即可
//
public void print(int n) {
System.out.println(“print()方法被调用 n=” + n);
}
public void sayOk() { //sayOk 调用 print(直接调用即可)
print(10);
System.out.println(“继续执行 sayOK()~~~”);
}
//跨类中的方法 A 类调用B 类方法:需要通过对象名调用
public void m1() {
//创建 B 对象, 然后在调用方法即可
System.out.println(“m1() 方法被调用”);
B b = new B();
b.hi();
System.out.println(“m1() 继续执行:)”);
}
}
class B {
public void hi() {
System.out.println(“B 类中的 hi()被执行”);
}
}
7.2.8类定义的完善
7.2.9课堂练习题
MethodExercise01.java
public class MethodExercise01 {
//编写一个 main 方法
public static void main(String[] args) {
AA a = new AA();
// if(a.isOdd(2)) {//T , 这样的写法以后会看到很多
// System.out.println(“是奇数”);
// } else {
// System.out.println(“是偶数”);
// }
//
//
// 使用 print 方法
a.print(4, 4, ‘#’);
}
}
//编写类 AA ,有一个方法:判断一个数是奇数 odd 还是偶数, 返回boolean
class AA {
//思路
//1. 方法的返回类型 boolean
//2. 方法的名字 isOdd
//3. 方法的形参 (int num)
//4. 方法体 , 判断
public boolean isOdd(int num) {
// if(num % 2 != 0) {
// return true;
// } else {
// return false;
// }
//return num % 2 != 0 ? true; false;
//
return num % 2 != 0;
}
//根据行、列、字符打印 对应行数和列数的字符,
//比如:行:4 ,列:4 ,字符#,则打印相应的效果
/*
*/
//思路
//1. 方法的返回类型 void
//2. 方法的名字 print
//3. 方法的形参 (int row, int col, char c)
//4. 方法体 , 循环
public void print(int row, int col, char c) {
for(int i = 0; i < row; i++) {
for(int j = 0;j < col; j++) {//输出每一行
System.out.print©;
}
System.out.println(); //换行
}
}
}
7.3 成员方法传参机制(非常非常重要)
方法的传参机制对我们今后的编程非常重要,一定要搞的清清楚楚明明白白。我们通过案例来学习
7.3. 1基本数据类型的传参机制
public class MethodParameter01 {
//编写一个 main 方法
public static void main(String[] args) {
int a = 10;
int b = 20;
//创建 AA 对象 名字 obj
AA obj = new AA();
obj.swap(a, b); //调用 swap
System.out.println(“main 方法 a=” + a + " b=" + b);//a= 10 b=20
}
}
class AA {
public void swap(int a,int b){
System.out.println(“\na 和 b 交换前的值\na=” + a + “\tb=” + b);//a= 10 b=20
//完成了 a 和 b 的交换
int tmp = a;
a = b;
b = tmp;
System.out.println(“\na 和 b 交换后的值\na=” + a + “\tb=” + b);//a=20 b=10
}
}
7.3.2引用数据类型的传参机制
化?会变化.
public class MethodParameter02 {
//编写一个 main 方法
public static void main(String[] args) {
//测试
B b = new B();
// int[] arr = { 1, 2, 3};
// b.test 100(arr);//调用方法
// System.out.println(" main 的 arr 数组 ");
// //遍历数组
// for(int i = 0; i < arr.length; i++) {
// System.out.print(arr[i] + “\t”);
// }
// System.out.println();
//测试
Person p = new Person();
p.name = “jack”;
p.age = 10;
b.test200§;
//测试题, 如果 test200 执行的是 p = null ,下面的结果是 10
//测试题, 如果 test200 执行的是 p = new Person();…, 下面输出的是 10
System.out.println(“main 的 p.age=” + p.age);//10000
}
}
class Person {
String name;
int age;
}
class B {
public void test200(Person p) {
//p.age = 10000; //修改对象属性
//思考
p = new Person();
p.name = “tom”;
p.age = 99;
//思考
//p = null;
}
//B 类中编写一个方法 test 100,
//可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化
public void test 100(int[] arr) {
arr[0] = 200;//修改元素
//遍历数组
System.out.println(" test 100 的 arr 数组 ");
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + “\t”);
}
System.out.println();
}
}
结论及示意图
引用类型传递的是地址 (传递也是值,但是值是地址) ,可以通过形参影响实参!
在看一个案例,下面的方法会对原来的对象有影响吗?
p=null 和 p = new Person(); 对应示意图
7.3.3成员方法返回类型是引用类型应用实例
MethodExercise02.java
public class MethodExercise02 {
//编写一个 main 方法
public static void main(String[] args) {
Person p = new Person();
p.name = “milan”;
p.age = 100;
//创建 tools
MyTools tools = new MyTools();
Person p2 = tools.copyPerson§;
//到此 p 和 p2 是 Person对象,但是是两个独立的对象,属性相同
System.out.println(“p 的属性 age=” + p.age + " 名字=" + p.name);
System.out.println(“p2 的属性 age=” + p2.age + " 名字=" + p2.name);
//这里老师提示: 可以同 对象比较看看是否为同一个对象
System.out.println(p == p2);//false
}
}
class Person {
String name;
int age;
}
class MyTools {
//编写一个方法 copyPerson ,可以复制一个 Person 对象,返回复制的对象。克隆对象,
//注意要求得到新对象和原来的对象是两个独立的对象,只是他们的属性相同
//
//编写方法的思路
//1. 方法的返回类型 Person
//2. 方法的名字 copyPerson
//3. 方法的形参 (Person p)
//4. 方法体, 创建一个新对象,并复制属性,返回即可
public Person copyPerson(Person p) {
//创建一个新的对象
Person p2 = new Person();
p2.name = p.name; //把原来对象的名字赋给 p2.name
p2.age = p.age; //把原来对象的年龄赋给 p2.age
return p2;
}
}
7.4 方法递归调用(非常非常重要,比较难)
7.4. 1基本介绍
简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题, 同时可以让代码变 得简洁
7.4.2递归能解决什么问题?
7.4.3递归举例
列举两个小案例,来帮助大家理解递归调用机制
public class Recursion01 {
//编写一个 main 方法
public static void main(String[] args) {
T t 1 = new T();
t 1.test(4);//输出什么? n=2 n=3 n=4
int res = t1.factorial(5);
System.out.println(“5 的阶乘 res =” + res);
}
}
class T {
//分析
public void test(int n) {
if (n > 2) {
test(n - 1);
}
System.out.println(“n=” + n);
}
//factorial 阶乘
public int factorial(int n) {
if (n == 1) {
return 1;
} else {
return factorial(n - 1) * n;
}
}
}
7.4.4递归重要规则
7.4.5课堂练习
RecursionExercise01.java
代码
public class RecursionExercise01 {
//编写一个 main 方法
public static void main(String[] args) {
T t 1 = new T();
// int n = 7;
// int res = t1.fibonacci(n);
// if(res != - 1) {
// System.out.println(“当 n=”+ n +" 对应的斐波那契数=" + res);
// }
//
//桃子问题
int day = 0;
int peachNum = t1.peach(day);
if(peachNum != - 1) {
System.out.println("第 " + day + “天有” + peachNum + “个桃子”);
}
}
}
class T {
/*
请使用递归的方式求出斐波那契数 1, 1,2,3,5,8, 13…给你一个整数 n ,求出它的值是多
思路分析
public int fibonacci(int n) {
if( n >= 1) {
if( n == 1 || n == 2) {
return 1;
} else {
return fibonacci(n- 1) + fibonacci(n-2);
}
} else {
System.out.println(“要求输入的 n>=1 的整数”);
return - 1;
}
}
/*
猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!
以后每天猴子都吃其中的一半,然后再多吃一个。当到第 10 天时,
想再吃时 (即还没吃) ,发现只有 1 个桃子了。问题:最初共多少个桃子?
思路分析 逆推
}
7.4.6递归调用应用实例-迷宫问题
MiGong.java
代码
public class MiGong {
//编写一个 main 方法
public static void main(String[] args) {
//思路
//1. 先创建迷宫,用二维数组表示 int[][] map = new int[8][7];
//2. 先规定 map 数组的元素值: 0 表示可以走 1 表示障碍物
int[][] map = new int[8][7];
//3. 将最上面的一行和最下面的一行,全部设置为 1
for(int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}
//4.将最右面的一列和最左面的一列,全部设置为 1
for(int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
}
map[3][1] = 1;
map[3][2] = 1;
map[2][2] = 1; //测试回溯
// map[2][1] = 1;
// map[2][2] = 1;
// map[ 1][2] = 1;
//输出当前的地图
System.out.println(“=当前地图情况==”);
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j] + " ");//输出一行
}
System.out.println();
}
//使用 findWay 给老鼠找路
T t 1 = new T();
//下右上左
t 1.findWay(map, 1, 1);
System.out.println(“\n找路的情况如下=”);
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j] + " ");//输出一行
}
System.out.println();
}
}
}
class T {
//使用递归回溯的思想来解决老鼠出迷宫
//老韩解读
//1. findWay 方法就是专门来找出迷宫的路径
//2. 如果找到,就返回 true ,否则返回 false
//3. map 就是二维数组,即表示迷宫
//4. i,j 就是老鼠的位置,初始化的位置为(1, 1)
//5. 因为我们是递归的找路,所以我先规定 map 数组的各个值的含义
// 0 表示可以走 1 表示障碍物 2 表示可以走 3 表示走过,但是走不通是死路
//6. 当 map[6][5] =2 就说明找到通路,就可以结束,否则就继续找.
//7. 先确定老鼠找路策略 下->右->上->左
public boolean findWay(int[][] map , int i, int j) {
if(map[6][5] == 2) {//说明已经找到
return true;
} else {
if(map[i][j] == 0) {//当前这个位置 0,说明表示可以走
//我们假定可以走通
map[i][j] = 2;
//使用找路策略,来确定该位置是否真的可以走通
//下->右->上->左
if(findWay(map, i + 1, j)) {//先走下
return true;
} else if(findWay(map, i, j + 1)){//右
return true;
} else if(findWay(map, i- 1, j)) {//上
return true;
} else if(findWay(map, i, j- 1)){//左
return true;
} else {
map[i][j] = 3;
return false;
}
} else { //map[i][j] = 1 , 2, 3
return false;
}
}
}
//修改找路策略,看看路径是否有变化
//下->右->上->左 ==> 上->右->下->左
public boolean findWay2(int[][] map , int i, int j) {
if(map[6][5] == 2) {//说明已经找到
return true;
} else {
if(map[i][j] == 0) {//当前这个位置 0,说明表示可以走
//我们假定可以走通
map[i][j] = 2;
//使用找路策略,来确定该位置是否真的可以走通
//上->右->下->左
if(findWay2(map, i - 1, j)) {//先走上
return true;
} else if(findWay2(map, i, j + 1)){//右
return true;
} else if(findWay2(map, i+1, j)) {//下
return true;
} else if(findWay2(map, i, j- 1)){//左
return true;
} else {
map[i][j] = 3;
return false;
}
} else { //map[i][j] = 1 , 2, 3
return false;
}
}
}
}
7.4.7递归调用应用实例-汉诺塔
汉诺塔传说
汉诺塔:汉诺塔 (又称河内塔) 问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子, 在一根柱子上从下往上按照大小顺序摞着 64 片圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一 根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
假如每秒钟移动一次,共需多长时间呢?移完这些金片需要 5845.54 亿年以上,太阳系的预期寿命据说也就是数百亿年。 真的过了 5845.54 亿年,地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭
汉诺塔代码实现
看老师代码演示 HanoiTower.java
代码
public class HanoiTower {
//编写一个 main 方法
public static void main(String[] args) {
Tower tower = new Tower();
tower.move(64, ‘A’, ‘B’, ‘C’);
}
}
class Tower {
//方法
//num 表示要移动的个数, a, b, c 分别表示 A 塔,B 塔, C 塔
public void move(int num , char a, char b ,char c) {
//如果只有一个盘 num = 1
if(num == 1) {
System.out.println(a + “->” + c);
} else {
//如果有多个盘,可以看成两个 , 最下面的和上面的所有盘(num- 1)
//(1)先移动上面所有的盘到 b, 借助 c
move(num - 1 , a, c, b);
//(2)把最下面的这个盘,移动到 c
System.out.println(a + “->” + c);
//(3)再把 b 塔的所有盘,移动到 c ,借助 a
move(num - 1, b, a, c);
}
}
}
7.4.8递归调用应用实例-八皇后问题[同学们先尝试做,后面老师评讲.]
八皇后问题说明
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯 · 贝瑟尔于 1848 年 提出:在 8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同 一斜线上,问有多少种摆法。
7.5 方法重载(OverLoad)
7.5. 1基本介绍
java 中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致!
比如:System.out.println(); out 是 PrintStream 类型
OverLoad01.java
7.5.2重载的好处
代码
public class OverLoad01 {
//编写一个 main 方法
public static void main(String[] args) {
// System.out.println( 100);
// System.out.println(“hello,world”);
// System.out.println(‘h’);
// System.out.println( 1. 1);
// System.out.println(true);
//
MyCalculator mc = new MyCalculator();
System.out.println(mc.calculate( 1, 2));
System.out.println(mc.calculate( 1. 1, 2));
System.out.println(mc.calculate( 1, 2. 1));
}
}
class MyCalculator {
//下面的四个 calculate 方法构成了重载
//两个整数的和
public int calculate(int n1, int n2) {
System.out.println(“calculate(int n1, int n2) 被调用”);
return n1 + n2;
}
//没有构成方法重载, 仍然是错误的,因为是方法的重复定义
// public void calculate(int n1, int n2) {
// System.out.println(“calculate(int n1, int n2) 被调用”);
// int res = n1 + n2;
// }
//看看下面是否构成重载, 没有构成,而是方法的重复定义,就错了
// public int calculate(int a1, int a2) {
// System.out.println(“calculate(int n1, int n2) 被调用”);
// return a1 + a2;
// }
//一个整数,一个 double 的和
public double calculate(int n1, double n2) {
return n1 + n2;
}
//一个 double ,一个 Int 和
public double calculate(double n1, int n2) {
System.out.println(“calculate(double n1, int n2) 被调用…”);
return n1 + n2;
}
//三个 int 的和
public int calculate(int n1, int n2,int n3) {
return n1 + n2 + n2;
}
}
7.5.4注意事项和使用细节
7.5.5课堂练习题
public class OverLoadExercise {
//编写一个 main 方法
public static void main(String[] args) {
//在主类的 main ()方法中分别用参数区别调用三个方法
Methods method = new Methods();
method.m( 10);//100
method.m( 10, 20);//200
method.m(“韩顺平教育 hello”);//字符串信息
//测试
System.out.println(method.max( 10, 24)); // 24
System.out.println(method.max( 10.0, 21.4)); // 21.4
System.out.println(method.max( 10.0, 1.4, 30.0)); // 30.0
}
}
/*
编写程序,类 Methods 中定义三个重载方法并调用。方法名为 m。
三个方法分别接收一个 int 参数、两个 int 参数、一个字符串参数。分别执行平方运算并输出结果, 相乘并输出结果,输出字符串信息。在主类的 main ()方法中分别用参数区别调用三个方法
定义三个重载方法 max() ,第一个方法,返回两个 int 值中的最大值,
第二个方法,返回两个 double 值中的最大值,第三个方法,
返回三个 double 值中的最大值,并分别调用三个方法
*/
class Methods {
//分析
//1 方法名 max
//2 形参 (int,int)
//3.int
public int max(int n1, int n2) {
return n1 > n2 ? n1 : n2;
}
//分析
//1 方法名 max
//2 形参 (double,double)
//3.double
public double max(double n1, double n2) {
return n1 > n2 ? n1 : n2;
}
//分析
//1 方法名 max
//2 形参 (double,double,double)
//3.double
public double max(double n1, double n2, double n3) {
System.out.println(“max(double n1, double n2, double n3)”);
//求出 n1 和 n2 的最大值
double max1 = n1 > n2 ? n1 : n2;
return max1 > n3 ? max1 : n3;
}
public double max(double n1, double n2, int n3) {
System.out.println(“max(double n1, double n2, int n3)”);
//求出 n1 和 n2 的最大值
double max1 = n1 > n2 ? n1 : n2;
return max1 > n3 ? max1 : n3;
}
//分析
//1 方法名 m
//2 形参 (int)
//3.void
public void m(int n) {
System.out.println(“平方=” + (n * n));
}
//1 方法名 m
//2 形参 (int, int)
//3.void
public void m(int n1, int n2) {
System.out.println(“相乘=” + (n1 * n2));
}
//1 方法名 m
//2 形参 (String)
//3.void
public void m(String str) {
System.out.println(“传入的 str=” + str);
}
}
7.6 可变参数
7.6. 1基本概念
java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。
就可以通过可变参数实现
7.6.2基本语法
访问修饰符 返回类型 方法名(数据类型… 形参名) {
}
7.6.3快速入门案例(VarParameter01.java)
看一个案例 类 HspMethod ,方法 sum 【可以计算 2 个数的和,3 个数的和 , 4. 5 , 。。】
public class VarParameter01 {
//编写一个 main 方法
public static void main(String[] args) {
HspMethod m = new HspMethod();
System.out.println(m.sum( 1, 5, 100)); //106
System.out.println(m.sum( 1, 19)); //20
}
}
class HspMethod {
//可以计算 2 个数的和,3 个数的和 , 4. 5 , 。。
//可以使用方法重载
// public int sum(int n1, int n2) {//2 个数的和
// return n1 + n2;
// }
// public int sum(int n1, int n2, int n3) {//3 个数的和
// return n1 + n2 + n3;
// }
// public int sum(int n1, int n2, int n3, int n4) {//4 个数的和
// return n1 + n2 + n3 + n4;
// }
//…
//上面的三个方法名称相同,功能相同, 参数个数不同-> 使用可变参数优化
//老韩解读
//1. int… 表示接受的是可变参数,类型是 int , 即可以接收多个 int(0-多)
//2. 使用可变参数时,可以当做数组来使用 即 nums 可以当做数组
//3. 遍历 nums 求和即可
public int sum(int… nums) {
//System.out.println(“接收的参数个数=” + nums.length);
int res = 0;
for(int i = 0; i < nums.length; i++) {
res += nums[i];
}
return res;
}
}
7.6.4注意事项和使用细节
代码
public class VarParameterDetail {
//编写一个 main 方法
public static void main(String[] args) {
//细节: 可变参数的实参可以为数组
int[] arr = { 1, 2, 3};
T t 1 = new T();
t 1.f1(arr);
}
}
class T {
public void f1(int… nums) {
System.out.println(“长度=” + nums.length);
}
//细节: 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
public void f2(String str, double… nums) {
}
//细节: 一个形参列表中只能出现一个可变参数
//下面的写法是错的.
// public void f3(int… nums1, double… nums2) {
// }
}
7.6.5课堂练习
public class VarParameterExercise {
//编写一个 main 方法
public static void main(String[] args) {
HspMethod hm = new HspMethod();
System.out.println(hm.showScore(“milan” , 90. 1, 80.0 ));
System.out.println(hm.showScore(“terry” , 90. 1, 80.0, 10,30.5,70 ));
}
}
class HspMethod {
/*
有三个方法,分别实现返回姓名和两门课成绩(总分),
返回姓名和三门课成绩(总分) ,返回姓名和五门课成绩 (总分) 。
封装成一个可变参数的方法
*/
//分析 1. 方法名 showScore 2. 形参(String ,double… ) 3. 返回 String
//听课小伙伴,老师要求必须自己动手写
public String showScore(String name ,double… scores ) {
double totalScore = 0;
for(int i = 0; i < scores.length; i++) {
totalScore += scores[i];
}
return name + " 有 " +scores.length + “门课的成绩总分为=” + totalScore;
}
}
7.7 作用域
7.7. 1基本使用
public class VarScope {
//编写一个 main 方法
public static void main(String[] args) {
}
}
class Cat {
//全局变量:也就是属性,作用域为整个类体 Cat 类:cry eat 等方法使用属性
//属性在定义时,可以直接赋值
int age = 10; //指定的值是 10
//全局变量(属性)可以不赋值,直接使用,因为有默认值,
double weight; //默认值是 0.0
public void hi() {
//局部变量必须赋值后,才能使用,因为没有默认值
int num = 1;
String address = “北京的猫”;
System.out.println(“num=” + num);
System.out.println(“address=” + address);
System.out.println(“weight=” + weight);//属性
}
public void cry() {
//1. 局部变量一般是指在成员方法中定义的变量
//2. n 和 name 就是局部变量
//3. n 和 name 的作用域在 cry 方法中
int n = 10;
String name = “jack”;
System.out.println(“在 cry 中使用属性 age=” + age);
}
public void eat() {
System.out.println(“在 eat 中使用属性 age=” + age);
//System.out.println(“在 eat 中使用 cry 的变量 name=” + name);//错误
}
}
7.7.2注意事项和细节使用
public class VarScopeDetail {
//编写一个 main 方法
public static void main(String[] args) {
Person p1 = new Person();
/*
属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。
局部变量,生命周期较短,伴随着它的代码块的执行而创建,
伴随着代码块的结束而销毁。即在一次方法调用过程中
*/
//p1.say();//当执行 say 方法时,say 方法的局部变量比如 name,会创建,当 say 执行完毕后 //name 局部变量就销毁,但是属性(全局变量)仍然可以使用
//
T t 1 = new T();
t 1.test(); //第 1 种跨类访问对象属性的方式
t 1.test2(p1);//第 2 种跨类访问对象属性的方式
}
}
class T {
//全局变量/属性:可以被本类使用,或其他类使用 (通过对象调用)
public void test() {
Person p1 = new Person();
System.out.println(p1.name);//jack
}
public void test2(Person p) {
System.out.println(p.name);//jack
}
}
class Person {
//细节: 属性可以加修饰符(public protected private…)
// 局部变量不能加修饰符
public int age = 20;
String name = “jack”;
public void say() {
//细节 属性和局部变量可以重名,访问时遵循就近原则
String name = “king”;
System.out.println(“say() name=” + name);
}
public void hi() {
String address = “北京”;
//String address = “上海”;//错误,重复定义变量
String name = “hsp”;//可以
}
}
7.8 构造方法/构造器
7.8. 1看一个需求
我们来看一个需求:前面我们在创建人类的对象时,是先把一个对象创建好后,再给他的年龄和姓名属性赋值,如 果现在我要求,在创建人类的对象时,就直接指定这个对象的年龄和姓名,该怎么做? 这时就可以使用构造器。
7.8.2基本语法
[修饰符] 方法名(形参列表){
方法体;
}
老韩说明:
构造器的修饰符可以默认, 也可以是 public protected private
构造器没有返回值
方法名 和类名字必须一样
参数列表 和 成员方法一样的规则
构造器的调用, 由系统完成
7.8.3基本介绍
构造方法又叫构造器(constructor) ,是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:
方法名和类名相同
没有返回值
在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。
7.8.4快速入门
现在我们就用构造方法来完成刚才提出的问题: 在创建人类的对象时 ,就直接指定这个对象的年龄和姓名
Constructor01.java
public class Constructor01 {
//编写一个 main 方法
public static void main(String[] args) {
//当我们 new 一个对象时,直接通过构造器指定名字和年龄
Person p1 = new Person(“smith”, 80);
System.out.println(“p1 的信息如下”);
System.out.println(“p1 对象 name=” + p1.name);//smith
System.out.println(“p1 对象 age=” + p1.age);//80
}
}
//在创建人类的对象时,就直接指定这个对象的年龄和姓名
//
class Person {
String name;
int age;
//构造器
//老韩解读
//1. 构造器没有返回值, 也不能写 void
//2. 构造器的名称和类 Person 一样
//3. (String pName, int pAge) 是构造器形参列表,规则和成员方法一样
public Person(String pName, int pAge) {
System.out.println(“构造器被调用~~ 完成对象的属性初始化”);
name = pName;
age = pAge;
}
}
7.8.5注意事项和使用细节
public class ConstructorDetail {
//编写一个 main 方法
public static void main(String[] args) {
Person p1 = new Person(“king”, 40);//第 1 个构造器
Person p2 = new Person(“tom”);//第 2 个构造器
Dog dog1 = new Dog();//使用的是默认的无参构造器
}
}
class Dog {
//如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器)
//使用javap 指令 反编译看看
/*
默认构造器
Dog() {
}
*/
//一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,
//除非显式的定义一下, 即: Dog(){} 写 (这点很重要)
//
public Dog(String dName) {
//…
}
Dog() { //显式的定义一下 无参构造器
}
}
class Person {
String name;
int age;//默认 0
//第 1 个构造器
public Person(String pName, int pAge) {
name = pName;
age = pAge;
}
//第 2 个构造器, 只指定人名,不需要指定年龄
public Person(String pName) {
name = pName;
}
}
7.8.6课堂练习题
ConstructorExercise.java
在前面定义的 Person类中添加两个构造器:
第一个无参构造器:利用构造器设置所有人的 age 属性初始值都为 18
第二个带 pName和 pAge 两个参数的构造器:使得每次创建 Person对象的同时初始化对象的 age 属性值和 name 属性值。 分别使用不同的构造器,创建对象.
代码:
public class ConstructorExercise {
//编写一个 main 方法
public static void main(String[] args) {
Person p1 = new Person();//无参构造器
//下面输出 name = null, age = 18
System.out.println(“p1 的信息 name=” + p1.name + " age=" + p1.age);
Person p2 = new Person(“scott”, 50);
//下面输出 name = scott, age = 50
System.out.println(“p2 的信息 name=” + p2.name + " age=" + p2.age);
}
}
/**
class Person {
String name;//默认值 null
int age;//默认 0
//第一个无参构造器:利用构造器设置所有人的 age 属性初始值都为 18
public Person() {
age = 18;//
}
//第二个带 pName 和 pAge 两个参数的构造器
public Person(String pName, int pAge) {
name = pName;
age = pAge;
}
}
7.9 对象创建的流程分析
7.9. 1看一个案例
学习完构造器后,我们类的定义就应该更加完善了
代码:
public class This01 {
//编写一个 main 方法
public static void main(String[] args) {
Dog dog1 = new Dog(“大壮”, 3);
System.out.println(“dog1 的 hashcode=” + dog1.hashCode());
//dog1 调用了 info()方法
dog1.info();
System.out.println(“============”);
Dog dog2 = new Dog(“大黄”, 2);
System.out.println(“dog2 的 hashcode=” + dog2.hashCode());
dog2.info();
}
}
class Dog{ //类
String name;
int age;
// public Dog(String dName, int dAge){//构造器
// name = dName;
// age = dAge;
// }
//如果我们构造器的形参,能够直接写成属性名,就更好了
//但是出现了一个问题,根据变量的作用域原则
//构造器的 name 是局部变量,而不是属性
//构造器的 age 是局部变量,而不是属性
//==> 引出 this 关键字来解决
public Dog(String name, int age){//构造器
//this.name 就是当前对象的属性 name
this.name = name;
//this.age 就是当前对象的属性 age
this.age = age;
System.out.println(“this.hashCode=” + this.hashCode());
}
public void info(){//成员方法,输出属性 x 信息
System.out.println(“this.hashCode=” + this.hashCode());
System.out.println(name + “\t” + age + “\t”);
}
}
10.2 深入理解 this
为了进一步理解 this,我们再看一个案例 (This01.java)
10.3 this 的注意事项和使用细节
ThisDetail.java
this 关键字可以用来访问本类的属性、方法、构造器
this 用于区分当前类的属性和局部变量
访问成员方法的语法:this.方法名(参数列表);
访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一 条语句)
this 不能在类定义的外部使用,只能在类定义的方法中使用。
public class TestPerson {
//编写一个 main 方法
public static void main(String[] args) {
Person p1 = new Person(“mary”, 20);
Person p2 = new Person(“mary”, 20);
System.out.println(“p1 和 p2 比较的结果=” + p1.compareTo(p2));
}
}
/*
定义 Person 类,里面有 name 、age 属性,并提供 compareTo 比较方法,
用于判断是否和另一个人相等,提供测试类 TestPerson 用于测试,
名字和年龄完全一样,就返回true, 否则返回 false
*/
class Person {
String name;
int age;
//构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//compareTo 比较方法
public boolean compareTo(Person p) {
//名字和年龄完全一样
// if(this.name.equals(p.name) && this.age == p.age) {
// return true;
// } else {
// return false;
// }
return this.name.equals(p.name) && this.age == p.age;
}
}
7. 11 本章作业
眼高手低->千万不要这样.->零基础
第 8 章 面向对象编程(中级部分)
8. 1 IDE (集成开发环境) -IDEA
8. 1. 1IDEA 介绍
老韩建议:
public class Hello {
public static void main(String[] args) {
System.out.println(“hello, idea, 你好北京~~”);
}
}
8.3.3IDEA 使用技巧和经验
设置字体 [如图] 和 颜色主题
菜单 file -> settings
字符编码设置
8.3.4课堂练习
使用 IDEA 开发一个java 项目 testpro01,创建一个类 MyTools, 编写一个方法,可以完成对 int 数组冒泡排序的功能 学员练习 , 使用快捷键的开发项目
8.3.5IDEA 常用快捷键
8.4 包
8.4. 1看一个应用场景
8.4.2包的三大作用
8.4.3包基本语法
8.4.4包的本质分析(原理)
8.4.5快速入门
8.4.6包的命名
8.4.7常用的包
一个包下,包含很多的类,java 中常用的包有:
package com.hspedu.pkg;
import java.util.Arrays;
//注意:
//老韩建议:我们需要使用到哪个类,就导入哪个类即可,不建议使用 导入
//import java.util.Scanner; //表示只会引入java.util 包下的 Scanner
//import java.util.;//表示将java.util 包下的所有类都引入(导入)
public class Import01 {
public static void main(String[] args) {
//使用系统提供 Arrays 完成 数组排序
int[] arr = {- 1, 20, 2, 13, 3};
//比如对其进行排序
//传统方法是, 自己编写排序(冒泡)
//系统是提供了相关的类,可以方便完成 Arrays
Arrays.sort(arr);
//输出排序结果
for (int i = 0; i < arr.length ; i++) {
System.out.print(arr[i] + “\t”);
}
}
}
8.4.9注意事项和使用细节
//package 的作用是声明当前类所在的包,需要放在类(或者文件)的最上面,
// 一个类中最多只有一句 package
package com.hspedu.pkg;
//import 指令 位置放在 package 的下面,在类定义前面,可以有多句且没有顺序要求
import java.util.Scanner;
import java.util.Arrays;
//…
//类定义
public class PkgDetail {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] arr = {0, - 1, 1};
Arrays.sort(args);
}
}
8.5 访问修饰符
8.5. 1基本介绍
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限 (范围) :
代码:
package com.hspedu.modifier;
public class A {
//四个属性,分别使用不同的访问修饰符来修饰
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public void m1() {
//在同一类中,可以访问 public protected 默认 private 修饰属性和方法
System.out.println(“n1=” + n1 + " n2=" + n2 + " n3=" + n3 + " n4=" + n4);
}
protected void m2() { }
void m3() { }
private void m4() { }
public void hi() {
//在同一类中,可以访问 public protected 默认 private 修饰属性和方法
m1();
m2();
m3();
m4();
}
}
package com.hspedu.modifier;
public class B {
public void say() {
A a = new A();
//在同一个包下,可以访问 public , protected 和 System.out.println(“n1=” + a.n1 + " n2=" + a.n2 +
默认修饰属性或方法,不能访问 private 属性或方法
" n3=" + a.n3 );
a.m1();
a.m2();
a.m3();
//a.m4(); 错误的
}
}
package com.hspedu.modifier;
public class Test {
public static void main(String[] args) {
A a = new A ();
a.m1();
B b = new B();
b.say();
}
}
//只有 默认和 public 可以修饰类
class Tiger{ }
8.6 面向对象编程三大特征
8.6. 1基本介绍
面向对象编程有三大特征:封装、继承和多态。
8.6.2封装介绍
8.6.3封装的理解和好处
8.6.4封装的实现步骤 (三步)
8.7 快速入门案例
看一个案例
package com.hspedu.encap;
public class Encapsulation01 {
public static void main(String[] args) {
//如果要使用快捷键 alt+r, 需要先配置主类
//第一次,我们使用鼠标点击形式运算程序,后面就可以用
Person person = new Person();
person.setName(“韩顺平”);
person.setAge(30);
person.setSalary(30000);
System.out.println(person.info());
System.out.println(person.getSalary());
//如果我们自己使用构造器指定属性
Person smith = new Person(“smith”, 80, 50000);
System.out.println(“smith 的信息==”);
System.out.println(smith.info());
}
}
/*
那么在java 中如何实现这种类似的控制呢?
请大家看一个小程序(com.hspedu.encap: Encapsulation01.java),
不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认 年龄, 必须在 1- 120, 年龄, 工资不能直接查看 , name 的长度在 2-6 字符 之间
*/
class Person {
public String name; //名字公开
private int age; //age 私有化
private double salary; //…
public void say(int n,String name) {
}
//构造器 alt+insert
public Person() {
}
//有三个属性的构造器
public Person(String name, int age, double salary) {
//
//
// this.name = name;
this.age = age;
this.salary = salary;
//我们可以将 set 方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
//自己写 setXxx 和 getXxx 太慢,我们使用快捷键
//然后根据要求来完善我们的代码.
public String getName() {
return name;
}
public void setName(String name) {
//加入对数据的校验,相当于增加了业务逻辑
if(name.length() >= 2 && name.length() <=6 ) {
this.name = name;
}else {
System.out.println(“名字的长度不对,需要(2-6)个字符,默认名字”);
this.name = “无名人”;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
//判断
if(age >= 1 && age <= 120) {//如果是合理范围
this.age = age;
} else {
System.out.println("你设置年龄不对,需要在 ( 1- 120), 给默认年龄 18 ");
this.age = 18;//给一个默认年龄
}
}
public double getSalary() {
//可以这里增加对当前对象的权限判断
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//写一个方法,返回属性信息
public String info() {
return “信息为 name=” + name + " age=" + age + " 薪水=" + salary;
}
}
8.7. 1将构造器和 setXxx 结合
看一个案例
//有三个属性的构造器
public Person(String name, int age, double salary) {
//
//
//
} this.name = name;
this.age = age;
this.salary = salary;
//我们可以将 set 方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
8.7.2课堂练习
package com.hspedu.encap;
/**
*/
public class Account {
//为了封装,将 3 个属性设置为 private
private String name;
private double balance;
private String pwd;
//提供两个构造器
public Account() {
}
public Account(String name, double balance, String pwd) {
this.setName(name);
this.setBalance(balance);
this.setPwd(pwd);
}
public String getName() {
return name;
}
//姓名 (长度为 2 位 3 位或 4 位)
public void setName(String name) {
if (name.length() >= 2 && name.length() <= 4) {
this.name = name;
} else {
System.out.println(“姓名要求 (长度为 2 位 3 位或 4 位) ,默认值 无名”);
this.name = “无名”;
}
}
public double getBalance() {
return balance;
}
//余额(必须>20)
public void setBalance(double balance) {
if (balance > 20) {
this.balance = balance;
} else {
System.out.println(“余额(必须>20) 默认为 0”);
}
}
public String getPwd() {
return pwd;
}
//密码 (必须是六位)
public void setPwd(String pwd) {
if (pwd.length() == 6) {
this.pwd = pwd;
} else {
System.out.println(“密码 (必须是六位) 默认密码为 000000”);
this.pwd = “000000”;
}
}
//显示账号信息
public void showInfo() {
//可以增加权限的校验
System.out.println(“账号信息 name=” + name + " 余额=" + balance + " 密码" + pwd);
//
//
//
//
//
}
} if() {
System.out.println(“账号信息 name=” + name + " 余额=" + balance + " 密码");
}else{
System.out.println(“你无权查看…”);
}
package com.hspedu.encap;
public class TestAccount {
public static void main(String[] args) {
//创建 Account
Account account = new Account();
account.setName(“jack”);
account.setBalance(60);
account.setPwd(“123456”);
account.showInfo();
}
}
8.8 面向对象编程-继承
8.8. 1为什么需要继承
8.8.2继承基本介绍和示意图
继承可以解决代码复用,让我们的编程更加靠近人类思维. 当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。画出继承的示意图
8.8.3继承的基本语法
8.8.4快速入门案例
我们对Extends01.java 改进,使用继承的方法,请大家注意体会使用继承的好处
package com.hspedu.extend_.improve_;
import com.hspedu.extend_.Graduate;
import com.hspedu.extend_.Pupil;
public class Extends01 {
public static void main(String[] args) {
com.hspedu.extend_.Pupil pupil = new Pupil();
pupil.name = “银角大王~”;
pupil.age = 11;
pupil.testing();
pupil.setScore(50);
pupil.showInfo();
System.out.println(“=======”);
com.hspedu.extend_.Graduate graduate = new Graduate();
graduate.name = “金角大王~”;
graduate.age = 23;
graduate.testing();
graduate.setScore(80);
graduate.showInfo();
}
}
package com.hspedu.extend_.improve_;
//父类,是 Pupil 和 Graduate 的父类
public class Student {
//共有属性
public String name;
public int age;
private double score;//成绩
//共有的方法
public void setScore(double score) {
this.score = score;
}
public void showInfo() {
System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
package com.hspedu.extend_.improve_;
//让 Pupil 继承 Student 类
public class Pupil extends Student {
public void testing() {
System.out.println(“小学生 " + name + " 正在考小学数学…”);
}
}
package com.hspedu.extend_.improve_;
public class Graduate extends Student {
public void testing() {//和 Pupil 不一样
System.out.println(“大学生 " + name + " 正在考大学数学…”);
}
}
8.8.5继承给编程带来的便利
代码的复用性提高了
代码的扩展性和维护性提高了
8.8.6继承的深入讨论/细节问题
子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
子类必须调用父类的构造器, 完成父类的初始化
当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译
不会通过(怎么理解。) [举例说明]
4) 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
5) super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
6) super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
7) java 所有类都是 Object 类的子类, Object 是所有类的基类.
8) 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
9) 子类最多只能继承一个父类(指直接继承) ,即java 中是单继承机制。
思考:如何让 A 类继承 B 类和C 类? 【A 继承 B , B 继承 C】
10) 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系
代码
package com.hspedu.extend_;
public class ExtendsDetail {
public static void main(String[] args) {
// System.out.println(“=第 1 个对象==”);
// Sub sub = new Sub(); //创建了子类对象 sub
// System.out.println(“=第 2 个对象==”);
// Sub sub2 = new Sub(“jack”); //创建了子类对象 sub2 System.out.println(“=第 3 对象==”);
Sub sub3 = new Sub(“king”, 10); //创建了子类对象 sub2 //sub.sayOk();
}
}
package com.hspedu.extend_;
public class Base extends TopBase { //父类
//4 个属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public Base() { //无参构造器
System.out.println(“父类 Base()构造器被调用…”);
}
public Base(String name, int age) {//有参构造器
//默认 super()
System.out.println(“父类 Base(String name, int age)构造器被调用…”);
}
public Base(String name) {//有参构造器
System.out.println(“父类 Base(String name)构造器被调用…”);
}
//父类提供一个 public 的方法,返回了 n4
public int getN4() {
return n4;
}
public void test 100() {
System.out.println(“test 100”);
}
protected void test200() {
System.out.println(“test200”);
}
void test300() {
System.out.println(“test300”);
}
private void test400() {
System.out.println(“test400”);
}
//call
public void callTest400() {
test400();
}
}
package com.hspedu.extend_;
import java.util.Arrays;
//输入 ctrl + H 可以看到类的继承关系
public class Sub extends Base { //子类
public Sub(String name, int age) {
//1. 老师要调用父类的无参构造器, 如下或者 什么都不写,默认就是调用 super()
//super();//父类的无参构造器
//2. 老师要调用父类的 Base(String name) 构造器
//super(“hsp”);
//3. 老师要调用父类的 Base(String name, int age) 构造器
super(“king”, 20);
//细节: super 在使用时,必须放在构造器第一行
//细节: super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器 //this() 不能再使用了
System.out.println(“子类 Sub(String name, int age)构造器被调用…”);
}
public Sub() {//无参构造器
//super(); //默认调用父类的无参构造器
super(“smith”, 10);
System.out.println(“子类 Sub()构造器被调用…”);
}
//当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器 public Sub(String name) {
super(“tom”, 30);
//do nothing…
System.out.println(“子类 Sub(String name)构造器被调用…”);
}
public void sayOk() {//子类方法
//非私有的属性和方法可以在子类直接访问
//但是私有属性和方法不能在子类直接访问
System.out.println(n1 + " " + n2 + " " + n3);
test 100();
test200();
test300();
//test400();错误
//要通过父类提供公共的方法去访问
System.out.println(“n4=” + getN4());
callTest400();//
}
}
package com.hspedu.extend_;
public class TopBase { //父类是 Object
public TopBase() {
//super(); Object 的无参构造器
System.out.println(“构造器 TopBase() 被调用…”);//1
}
}
8.8.7继承的本质分析(重要)
案例
package com.hspedu.extend_;
/**
class GrandPa { //爷类
String name = “大头爷爷”;
String hobby = “旅游”;
}
class Father extends GrandPa {//父类
String name = “大头爸爸”;
private int age = 39;
public int getAge() {
return age;
}
}
class Son extends Father { //子类
String name = “大头儿子”;
}
子类创建的内存布局
8.8.8课堂练习
案例 1 ExtendsExercise01.java
案例 2 ExtendsExercise02.java
package com.hspedu.extend_.exercise;
public class ExtendsExercise02 {
public static void main(String[] args) {
C c = new C();
}
}
class A {//A 类
public A() {
System.out.println(“我是 A 类”);
}
}
class B extends A { //B 类,继承 A 类 //main 方法中: C c =new C(); 输出么内容? 3min
public B() {
System.out.println(“我是 B 类的无参构造”);
}
public B(String name) {
System.out.println(name + “我是 B 类的有参构造”);
}
}
class C extends B { //C 类,继承 B 类
public C() {
this(“hello”);
System.out.println(“我是 c 类的无参构造”);
}
public C(String name) {
super(“hahah”);
System.out.println(“我是 c 类的有参构造”);
}
}
package com.hspedu.extend_.exercise;
//编写 Computer 类,包含 CPU 、内存、硬盘等属性,getDetails 方法用于返回 Computer 的详细信息 public class Computer {
private String cpu;
private int memory;
private int disk;
public Computer(String cpu, int memory, int disk) {
this.cpu = cpu;
this.memory = memory;
this.disk = disk;
}
//返回 Computer 信息
public String getDetails() {
return “cpu=” + cpu + " memory=" + memory + " disk=" + disk;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public int getMemory() {
return memory;
}
public void setMemory(int memory) {
this.memory = memory;
}
public int getDisk() {
return disk;
}
public void setDisk(int disk) {
this.disk = disk;
}
}
package com.hspedu.extend_.exercise;
//编写 PC 子类,继承 Computer 类,添加特有属性【品牌 brand】
public class PC extends Computer{
private String brand;
//这里 IDEA 根据继承的规则, 自动把构造器的调用写好
//这里也体现: 继承设计的基本思想,父类的构造器完成父类属性初始化
//子类的构造器完成子类属性初始化
public PC(String cpu, int memory, int disk, String brand) {
super(cpu, memory, disk);
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void printInfo() {
System.out.println(“PC 信息=”);
//
} System.out.println(getCpu() + getMemory() + getDisk());
//调用父类的 getDetails 方法,得到相关属性信息…
System.out.println(getDetails() + " brand=" + brand);
}
package com.hspedu.extend_.exercise;
public class ExtendsExercise03 {
public static void main(String[] args) {
PC pc = new PC(“intel”, 16, 500, “IBM”);
pc.printInfo();
}
}
/*
编写 Computer 类,包含 CPU 、内存、硬盘等属性,getDetails 方法用于返回 Computer 的详细信息 编写 PC 子类,继承 Computer 类,添加特有属性【品牌 brand】
编写 NotePad 子类,继承 Computer 类,添加特有属性【color】//同学们自己写。
编写 Test 类,在 main 方法中创建 PC 和 NotePad 对象,分别给对象中特有的属性赋值,
以及从 Computer 类继承的属性赋值,并使用方法并打印输出信息
*/
8.9 super 关键字
8.9. 1基本介绍
super 代表父类的引用,用于访问父类的属性、方法、构造器
8.9.2基本语法
代码
package com.hspedu.super_;
public class A extends Base{
//4 个属性
//public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public A() {}
public A(String name) {}
public A(String name, int age) {}
// public void cal() {
// System.out.println(“A 类的 cal() 方法…”);
// }
public void test 100() {
}
protected void test200() {
}
void test300() {
}
private void test400() {
}
}
package com.hspedu.super_;
public class B extends A {
public int n1 = 888;
//编写测试方法
public void test() {
//super 的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用 super 去访问爷爷类的成员; // 如果多个基类(上级类)中都有同名的成员,使用 super 访问遵循就近原则。A->B->C
System.out.println(“super.n1=” + super.n1);
super.cal();
}
//访问父类的属性 , 但不能访问父类的 private 属性 [案例]super.属性名
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3 );
}
public void cal() {
System.out.println(“B 类的 cal() 方法…”);
}
public void sum() {
System.out.println(“B 类的 sum()”);
//希望调用父类-A 的 cal 方法
//这时,因为子类 B 没有 cal 方法,因此我可以使用下面三种方式
//找 cal 方法时(cal() 和 this.cal()) ,顺序是:
// (1)先找本类,如果有,则调用
// (2)如果没有,则找父类(如果有,并可以调用,则调用)
// (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object 类
// 提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
//cal();
this.cal(); //等价 cal
//找 cal 方法(super.call()) 的顺序是直接查找父类,其他的规则一样
//super.cal();
//演示访问属性的规则
//n1 和 this.n1 查找的规则是
//(1) 先找本类,如果有,则调用
//(2) 如果没有,则找父类(如果有,并可以调用,则调用)
//(3) 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object 类
// 提示:如果查找属性的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找属性的过程中,没有找到,则提示属性不存在
System.out.println(n1);
System.out.println(this.n1);
//找 n1 (super.n1) 的顺序是直接查找父类属性,其他的规则一样
System.out.println(super.n1);
}
//访问父类的方法,不能访问父类的 private 方法 super.方法名(参数列表);
public void ok() {
super.test 100();
super.test200();
super.test300();
//super.test400();//不能访问父类 private 方法
}
//访问父类的构造器(这点前面用过):super(参数列表);只能放在构造器的第一句,只能出现一句! public B() {
//super();
//super(“jack”, 10);
super(“jack”);
}
}
package com.hspedu.super_;
public class Super01 {
public static void main(String[] args) {
B b = new B();//子类对象
//b.sum();
b.test();
}
}
package com.hspedu.super_;
public class Base { //父类是 Object
public int n1 = 999;
public int age = 111;
public void cal() {
System.out.println(“Base 类的 cal() 方法…”);
}
public void eat() {
}
}
8.9.3super 给编程带来的便利/细节
代码, 看前面的案例即可:
8.9.4super 和 this 的比较
10 方法重写/覆盖(override)
10.2 快速入门
代码
package com.hspedu.override_;
public class Animal {
public void cry() {
System.out.println(“动物叫唤…”);
}
public Object m1() {
return null;
}
public String m2() {
return null;
}
public AAA m3() {
return null;
}
protected void eat() {
}
}
package com.hspedu.override_;
public class Dog extends Animal{
//老韩解读
//1. 因为 Dog 是 Animal 子类
//2. Dog 的 cry 方法和 Animal 的 cry 定义形式一样(名称、返回类型、参数)
//3. 这时我们就说 Dog 的 cry 方法,重写了 Animal 的 cry 方法
public void cry() {
System.out.println(“小狗汪汪叫…”);
}
//细节: 子类方法的返回类型和父类方法返回类型一样,
// 或者是父类返回类型的子类
比如 父类 返回类型是 Object ,
// 子类方法返回类型是 String
public String m1() {
return null;
}
//这里 Object 不是 String 的子类,因此编译错误
// public Object m2() {
// return null;
// }
// public BBB m3() {
// return null;
// }
//细节: 子类方法不能缩小父类方法的访问权限 【演示】
//public > protected > 默认>private
public void eat() {
}
}
class AAA {
}
class BBB extends AAA {
}
package com.hspedu.override_;
public class Override01 {
public static void main(String[] args) {
//演示方法重写的情况
Dog dog = new Dog();
dog.cry();//ctrl+b
}
}
10.3 注意事项和使用细节
方法重写也叫方法覆盖,需要满足下面的条件
10.4 课堂练习
题 1
请对方法的重写和重载做一个比较
题 2
package com.hspedu.override_;
//编写一个 Person 类,包括属性/private (name 、age) ,构造器、方法 say(返回自我介绍的字符串) public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String say() {
return “name=” + name + " age=" + age;
}
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;
}
}
package com.hspedu.override_;
//编写一个 Student 类,继承 Person 类,增加 id 、score 属性/private ,以及构造器,定义 say 方法(返回自我介绍的信息)。 public class Student extends Person{
private int id;
private double score;
public Student(String name, int age, int id, double score) {
super(name, age);//这里会调用父类构造器
this.id = id;
this.score = score;
}
//say
public String say() { //这里体现 super 的一个好处,代码复用.
return super.say() + " id=" + id + " score=" + score;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
package com.hspedu.override_;
public class OverrideExercise {
public static void main(String[] args) {
//在 main 中,分别创建 Person 和 Student 对象,调用 say 方法输出自我介绍
Person jack = new Person(“jack”, 10);
System.out.println(jack.say());
Student smith = new Student(“smith”, 20, 123456, 99.8);
System.out.println(smith.say());
}
}
使用传统的方法来解决 (private 属性)
传统的方法带来的问题是什么? 如何解决?
问题是: 代码的复用性不高,而且不利于代码维护
解决方案: 引出我们要讲解的多态
代码:
package com.hspedu.poly_;
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.hspedu.poly_;
public class Bone extends Food {
public Bone(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class Fish extends Food {
public Fish(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.hspedu.poly_;
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//使用多态机制,可以统一的管理主人喂食的问题
//animal 编译类型是 Animal,可以指向(接收)Animal 子类的对象
//food 编译类型是 Food ,可以指向(接收) Food 子类的对象
public void feed(Animal animal, Food food) {
System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName()); }
//主人给小狗 喂食 骨头
// public void feed(Dog dog, Bone bone) {
// System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());
// }
// //主人给 小猫喂 黄花鱼
// public void feed(Cat cat, Fish fish) {
// System.out.println("主人 " + name + " 给 " + cat.getName() + " 吃 " + fish.getName());
// }
//如果动物很多,食物很多
//===> feed 方法很多,不利于管理和维护
//Pig --> Rice
//Tiger —> meat …
//…
}
package com.hspedu.poly_;
public class Pig extends Animal {
public Pig(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class Rice extends Food {
public Rice(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class PloyMethod {
public static void main(String[] args) {
//方法重载体现多态
A a = new A();
//这里我们传入不同的参数,就会调用不同 sum 方法,就体现多态
System.out.println(a.sum( 10, 20));
System.out.println(a.sum( 10, 20, 30));
//方法重写体现多态
B b = new B();
a.say();
b.say();
}
}
class B { //父类
public void say() {
System.out.println(“B say() 方法被调用…”);
}
}
class A extends B {//子类
public int sum(int n1, int n2){//和下面 sum 构成重载
return n1 + n2;
}
public int sum(int n1, int n2, int n3){
return n1 + n2 + n3;
}
public void say() {
System.out.println(“A say() 方法被调用…”);
}
}
代码:
package com.hspedu.poly_.objectpoly_;
public class Animal {
public void cry() {
System.out.println(“Animal cry() 动物在叫…”);
}
}
package com.hspedu.poly_.objectpoly_;
public class Cat extends Animal {
public void cry() {
System.out.println(“Cat cry() 小猫喵喵叫…”);
}
}
package com.hspedu.poly_.objectpoly_;
public class Dog extends Animal {
public void cry() {
System.out.println(“Dog cry() 小狗汪汪叫…”);
}
}
package com.hspedu.poly_.objectpoly_;
public class PolyObject {
public static void main(String[] args) {
//体验对象多态特点
//animal 编译类型就是 Animal , 运行类型 Dog
Animal animal = new Dog();
//因为运行时 , 执行到改行时,animal 运行类型是 Dog,所以 cry 就是 Dog 的 cry
animal.cry(); //小狗汪汪叫
//animal 编译类型 Animal,运行类型就是 Cat
animal = new Cat();
animal.cry(); //小猫喵喵叫
}
}
11.4 多态快速入门案例
使用多态的机制来解决主人喂食物的问题,走代码。 Poly01.java
11.5 多态注意事项和细节讨论
com.hspedu.poly_.detail_ 包 : PolyDetail.java
多态的前提是:两个对象(类)存在继承关系
多态的向上转型
多态向下转型
package com.hspedu.poly_.detail_;
public class Animal {
String name = “动物”;
int age = 10;
public void sleep(){
System.out.println(“睡”);
}
public void run(){
System.out.println(“跑”);
}
public void eat(){
System.out.println(“吃”);
}
public void show(){
System.out.println(“hello,你好”);
}
}
package com.hspedu.poly_.detail_;
public class Cat extends Animal {
public void eat(){//方法重写
System.out.println(“猫吃鱼”);
}
public void catchMouse(){//Cat 特有方法
System.out.println(“猫抓老鼠”);
}
}
package com.hspedu.poly_.detail_;
public class Dog extends Animal {//Dog 是 Animal 的子类
}
package com.hspedu.poly_.detail_;
public class PolyDetail {
public static void main(String[] args) {
//向上转型: 父类的引用指向了子类的对象
//语法:父类类型引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类
//向上转型调用方法的规则如下:
//(1)可以调用父类中的所有成员(需遵守访问权限)
//(2)但是不能调用子类的特有的成员
//(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
//animal.catchMouse();错误
//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法 // ,然后调用,规则我前面我们讲的方法调用规则一致。
animal.eat();//猫吃鱼…
animal.run();//跑
animal.show();//hello,你好
animal.sleep();//睡
//老师希望,可以调用 Cat 的 catchMouse 方法
//多态的向下转型
//(1)语法:子类类型 引用名 = (子类类型) 父类引用;
//问一个问题? cat 的编译类型 Cat,运行类型是 Cat
Cat cat = (Cat) animal;
cat.catchMouse();//猫抓老鼠
//(2)要求父类的引用必须指向的是当前目标类型的对象
Dog dog = (Dog) animal; //可以吗?
System.out.println(“ok~~”);
}
}
属性没有重写之说!属性的值看编译类型 PolyDetail02.java
package com.hspedu.poly_.detail_;
public class PolyDetail02 {
public static void main(String[] args) {
//属性没有重写之说!属性的值看编译类型
Base base = new Sub();//向上转型
System.out.println(base.count);// ? 看编译类型 10
Sub sub = new Sub();
System.out.println(sub.count);//? 20
}
}
class Base { //父类
int count = 10;//属性
}
class Sub extends Base {//子类
int count = 20;//属性
}
instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型【举例说明】PolyDetail03.java
package com.hspedu.poly_.detail_;
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
//aa 编译类型 AA, 运行类型是 BB
//BB 是 AA 子类
AA aa = new BB();
System.out.println(aa instanceof AA);
System.out.println(aa instanceof BB);
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = “hello”;
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA {} //父类
class BB extends AA {}//子类
PolyExercise02.java 3min
代码
package com.hspedu.poly_.dynamic_;
public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型 A, 运行类型 B
A a = new B();//向上转型
System.out.println(a.sum());//?40 -> 30
System.out.println(a.sum1());//?30-> 20
}
}
class A {//父类
public int i = 10;
//动态绑定机制:
public int sum() {//父类 sum()
return getI() + 10;//20 + 10
}
public int sum1() {//父类 sum1()
return i + 10;//10 + 10
}
public int getI() {//父类 getI
return i;
}
}
class B extends A {//子类
public int i = 20;
// public int sum() {
// return i + 20;
// }
public int getI() {//子类 getI()
return i;
}
// public int sum1() {
// return i + 10;
// }
}
应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组
中,并调用每个对象
say 方法.
应用实例升级:如何调用子类特有的方法,比如
Teacher 有一个 teach , Student 有一个 study
怎么调用?
代码:
package com.hspedu.poly_.polyarr_;
public class Person {//父类
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
public String say() {//返回名字和年龄
return name + “\t” + age;
}
}
package com.hspedu.poly_.polyarr_;
public class Student extends Person {
private double score;
public Student(String name, int age, double score) {
super(name, age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
//重写父类 say
@Override
public String say() {
return “学生 " + super.say() + " score=” + score;
}
//特有的方法
public void study() {
System.out.println(“学生 " + getName() + " 正在学java…”);
}
}
package com.hspedu.poly_.polyarr_;
public class Teacher extends Person {
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//写重写父类的 say 方法
@Override
public String say() {
return “老师 " + super.say() + " salary=” + salary;
}
//特有方法
public void teach() {
System.out.println(“老师 " + getName() + " 正在讲java 课程…”);
}
}
package com.hspedu.poly_.polyarr_;
public class PloyArray {
public static void main(String[] args) {
//应用实例:现有一个继承结构如下:要求创建 1 个 Person对象、
//2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象 say 方法
Person[] persons = new Person[5];
persons[0] = new Person(“jack”, 20);
persons[ 1] = new Student(“mary”, 18, 100);
persons[2] = new Student(“smith”, 19, 30. 1);
persons[3] = new Teacher(“scott”, 30, 20000);
persons[4] = new Teacher(“king”, 50, 25000);
//循环遍历多态数组,调用 say
for (int i = 0; i < persons.length; i++) {
//老师提示: person[i] 编译类型是 Person ,运行类型是是根据实际情况有 JVM 来判断
System.out.println(persons[i].say());//动态绑定机制
//这里大家聪明. 使用 类型判断 + 向下转型.
if(persons[i] instanceof Student) {//判断 person[i] 的运行类型是不是 Student
Student student = (Student)persons[i];//向下转型
student.study();
//小伙伴也可以使用一条语句 ((Student)persons[i]).study();
} else if(persons[i] instanceof Teacher) {
Teacher teacher = (Teacher)persons[i];
teacher.teach();
} else if(persons[i] instanceof Person){
//System.out.println(“你的类型有误, 请自己检查…”);
} else {
System.out.println(“你的类型有误, 请自己检查…”);
}
}
}
}
代码:
package com.hspedu.poly_.polyparameter_;
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
//得到年工资的方法
public double getAnnual() {
return 12 * salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.hspedu.poly_.polyparameter_;
public class Manager extends Employee{
private double bonus;
public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public void manage() {
System.out.println(“经理 " + getName() + " is managing”);
}
//重写获取年薪方法
@Override
public double getAnnual() {
return super.getAnnual() + bonus;
}
}
package com.hspedu.poly_.polyparameter_;
public class Worker extends Employee {
public Worker(String name, double salary) {
super(name, salary);
}
public void work() {
System.out.println(“普通员工 " + getName() + " is working”);
}
@Override
public double getAnnual() { //因为普通员工没有其它收入,则直接调用父类方法
return super.getAnnual();
}
}
package com.hspedu.poly_.polyparameter_;
public class PloyParameter {
public static void main(String[] args) {
Worker tom = new Worker(“tom”, 2500);
Manager milan = new Manager(“milan”, 5000, 200000);
PloyParameter ployParameter = new PloyParameter();
ployParameter.showEmpAnnual(tom);
ployParameter.showEmpAnnual(milan);
ployParameter.testWork(tom);
ployParameter.testWork(milan);
}
//showEmpAnnual(Employee e)
//实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [e.getAnnual()]
public void showEmpAnnual(Employee e) {
System.out.println(e.getAnnual());//动态绑定机制.
}
//添加一个方法,testWork,如果是普通员工,则调用 work 方法,如果是经理,则调用 manage 方法 public void testWork(Employee e) {
if(e instanceof Worker) {
((Worker) e).work();//有向下转型操作
} else if(e instanceof Manager) {
((Manager) e).manage();//有向下转型操作
} else {
System.out.println(“不做处理…”);
}
}
}
package com.hspedu.object_;
public class Equals01 {
public static void main(String[] args) {
A a = new A();
A b = a;
A c = b;
System.out.println(a == c);//true
System.out.println(b == c);//true
B bObj = a;
System.out.println(bObj == c);//true
int num1 = 10;
double num2 = 10.0;
System.out.println(num1 == num2);//基本数据类型,判断值是否相等
//equals 方法,源码怎么查看.
//把光标放在 equals 方法,直接输入 ctrl+b
//如果你使用不了. 自己配置. 即可使用.
/*
//带大家看看 Jdk 的源码 String 类的 equals 方法
//把 Object 的 equals 方法重写了,变成了比较两个字符串值是否相同
public boolean equals(Object anObject) {
if (this == anObject) {//如果是同一个对象
return true;//返回 true
}
if (anObject instanceof String) {//判断类型
String anotherString = (String)anObject;//向下转型
int n = value.length;
if (n == anotherString.value.length) {//如果长度相同
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {//然后一个一个的比较字符
if (v1[i] != v2[i])
return false;
i++;
}
return true;//如果两个字符串的所有字符都相等,则返回 true
}
}
return false;//如果比较的不是字符串,则直接返回 false
}
*/
“hello”.equals(“abc”);
//看看 Object 类的 equals 是
/*
//即 Object 的 equals 方法默认就是比较对象地址是否相同
//也就是判断两个对象是不是同一个对象.
public boolean equals(Object obj) {
return (this == obj);
}
*/
/*
//从源码可以看到 Integer 也重写了 Object 的 equals 方法,
//变成了判断两个值是否相同
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
*/
Integer integer1 = new Integer( 1000);
Integer integer2 = new Integer( 1000);
System.out.println(integer1 == integer2);//false
System.out.println(integer1.equals(integer2));//true
String str1 = new String(“hspedu”);
String str2 = new String(“hspedu”);
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//true
}
}
class B {}
class A extends B {}
EqualsExercise01.java
package com.hspedu.object_;
public class EqualsExercise01 {
public static void main(String[] args) {
Person person1 = new Person(“jack”, 10, ‘男’);
Person person2 = new Person(“jack”, 20, ‘男’);
System.out.println(person1.equals(person2));//假
}
}
//判断两个 Person 对象的内容是否相等,
//如果两个 Person 对象的各个属性值都一样,则返回true ,反之 false
class Person{ //extends Object
private String name;
private int age;
private char gender;
//重写 Object 的 equals 方法
public boolean equals(Object obj) {
//判断如果比较的两个对象是同一个对象,则直接返回true
if(this == obj) {
return true;
}
//类型判断
if(obj instanceof Person) {//是 Person ,我们才比较
//进行 向下转型, 因为我需要得到 obj 的 各个属性
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
}
//如果不是 Person ,则直接返回 false
return false;
}
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
8. 12.3 课堂练习题
package com.hspedu.object_;
public class EqualsExercise02 {
public static void main(String[] args) {
Person_ p1 = new Person_();
p1.name = “hspedu”;
Person_ p2 = new Person_();
p2.name = “hspedu”;
System.out.println(p1==p2); //False
System.out.println(p1.name .equals( p2.name));//T
System.out.println(p1.equals(p2));//False
String s1 = new String(“asdf”);
String s2 = new String(“asdf”);
System.out.println(s1.equals(s2));//T
System.out.println(s1==s2); //F
}
}
class Person_ {//类
public String name;
}
代码如下 EqualsExercise03.java 2min
//代码如下 EqualsExercise03.java 2min
int it = 65;
float fl = 65.0f;
System.out.println(“65 和 65.0f 是否相等?” + (it == fl));//T
char ch 1 = ‘A’; char ch2 = 12;
System.out.println(“65 和‘A’是否相等?” + (it == ch 1));//T
System.out.println(“12 和 ch2 是否相等?” + (12 == ch2));//T
String str1 = new String(“hello”);
String str2 = new String(“hello”);
System.out.println(“str1 和 str2 是否相等?”+ (str1 == str2)); //F
System.out.println(“str1 是否 equals str2?”+(str1.equals(str2)));//T
System.out.println(“hello” == new java.sql.Date()); //编译错误
老韩的6 个小结:
提高具有哈希结构的容器的效率!
两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
两个引用,如果指向的是不同对象,则哈希值是不一样的
哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址。
案例演示[HashCode_.java]: obj.hashCode() [测试:A obj1 = new A(); A obj2 = new A(); A obj3 = obj1]
后面在集合,中 hashCode 如果需要的话,也会重写, 在讲解集合时,老韩在说如何重写 hashCode() 代码
package com.hspedu.object_;
public class HashCode_ {
public static void main(String[] args) {
AA aa = new AA();
AA aa2 = new AA();
AA aa3 = aa;
System.out.println(“aa.hashCode()=” + aa.hashCode());
System.out.println(“aa2.hashCode()=” + aa2.hashCode());
System.out.println(“aa3.hashCode()=” + aa3.hashCode());
}
}
class AA {}
案例演示:Monster [name, job, sal] 案例: ToString_.java
3) 当直接输 出 一个对 象 时 ,toString 方法会被默认 的调用 , 比 如 System.out.println(monster) ; 就会默认调用
monster.toString()
代码:
package com.hspedu.object_;
public class ToString_ {
public static void main(String[] args) {
/*
Object 的 toString() 源码
( 1)getClass().getName() 类的全类名(包名+类名 )
(2)Integer.toHexString(hashCode()) 将对象的 hashCode 值转成 16 进制字符串 public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}
*/
Monster monster = new Monster(“小妖怪”, “巡山的”, 1000);
System.out.println(monster.toString() + " hashcode=" + monster.hashCode());
System.out.println(“当直接输出一个对象时,toString 方法会被默认的调用”);
System.out.println(monster); //等价 monster.toString()
}
}
class Monster {
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
//重写 toString 方法, 输出对象的属性
//使用快捷键即可 alt+insert -> toString
@Override
public String toString() { //重写后,一般是把对象的属性值输出,当然程序员也可以自己定制 return “Monster{” +
“name='” + name + ‘’’ +
“, job='” + job + ‘’’ +
“, sal=” + sal +
‘}’;
}
@Override
protected void finalize() throws Throwable {
System.out.println(“fin…”);
}
}
8. 12.6 finalize 方法
当对象被回收时,系统自动调用该对象的finalize 方法。子类可以重写该方法,做一些释放资源的操作【演示】
什么时候被回收:当某个对象没有任何引用时,则jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来 销毁该对象,在销毁该对象前,会先调用 finalize 方法。
垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制,测 试:Car [name]
老韩提示: 我们在实际开发中,几乎不会运用 finalize , 所以更多就是为了应付面试.
代码:
package com.hspedu.object_;
//演示 Finalize 的用法
public class Finalize_ {
public static void main(String[] args) {
Car bmw = new Car(“宝马”);
//这时 car 对象就是一个垃圾,垃圾回收器就会回收(销毁)对象, 在销毁对象前,会调用该对象的finalize 方法 //,程序员就可以在 finalize 中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件…)
//,如果程序员不重写 finalize,那么就会调用 Object 类的 finalize, 即默认处理
//,如果程序员重写了 finalize, 就可以实现自己的逻辑
bmw = null;
System.gc();//主动调用垃圾回收器
System.out.println(“程序退出了…”);
}
}
class Car {
private String name;
//属性, 资源。。
public Car(String name) {
this.name = name;
}
//重写 finalize
@Override
protected void finalize() throws Throwable {
System.out.println(“我们销毁 汽车” + name );
System.out.println(“释放了某些资源…”);
}
}
13 断点调试(debug)
13.2 断点调试介绍
13.3 断点调试的快捷键
F7(跳入) F8(跳过) shift+F8(跳出) F9(resume,执行到下一个断点)
F7:跳入方法内
F8: 逐行执行代码.
shift+F8: 跳出方法
13.4 断点调试应用案例
看几段代码,演示调试过程
13.5 断点调试应用案例
package com.hspedu.debug_;
public class Debug01 {
public static void main(String[] args) {
//演示逐行执行代码
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += i;
System.out.println(“i=” + i);
System.out.println(“sum=” + i);
}
System.out.println(“退出 for…”);
}
}
package com.hspedu.debug_;
public class Debug02 {
public static void main(String[] args) {
int[] arr = { 1, 10, - 1};
for (int i = 0; i <= arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println(“退出 for”);
}
}
package com.hspedu.debug_;
import java.util.Arrays;
public class Debug03 {
public static void main(String[] args) {
int[] arr = { 1, - 1, 10, -20 , 100};
//我们看看 Arrays.sort 方法底层实现.->Debug
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + “\t”);
}
}
}
package com.hspedu.debug_;
import java.util.Arrays;
//演示执行到下一个断点,同时支持动态的下断点.
public class Debug04 {
public static void main(String[] args) {
int[] arr = { 1, - 1, 10, -20 , 100};
//我们看看 Arrays.sort 方法底层实现.->Debug
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + “\t”);
}
System.out.println(“hello100”);
System.out.println(“hello200”);
System.out.println(“hello300”);
System.out.println(“hello400”);
System.out.println(“hello500”);
System.out.println(“hello600”);
System.out.println(“hello700”);
}
}
8. 13.6 断点调试课后练习
化繁为简.
编写文件 SmallChangeSys.java 完成基本功能 (过程编程)
老师提示:先使用过程编程,后面改成 OOP 版本,请小伙伴体会 OOP 编程带来的好处
8. 14.5 项目代码实现改进
项目代码打包:
smallchange.zip
第 9 章 项目-房屋出租系统
9. 1 房屋出租系统-需求
9. 1. 1项目需求说明
实现基于文本界面的《房屋出租软件》。
能够实现对房屋信息的添加、修改和删除 (用数组实现) ,并能够打印房屋明细表
9.2 房屋出租系统-界面
9.2. 1项目界面 - 主菜单
9.2.2项目界面- 新增房源
9.2.3项目界面- 查找房源
9.2.4项目界面- 删除房源
9.2.5项目界面- 修改房源
9.2.6项目界面- 房屋列表
9.2.7项目界面- 退出系统
9.3 房屋出租系统-设计(!!)
项目设计-程序框架图 (分层模式=>当软件比较复杂,需要模式管理)
9.4 房屋出租系统-实现
9.4. 1准备工具类 Utility ,提高开发效率
在实际开发中,公司都会提供相应的工具类和开发库,可以提高开发效率,程序员也需要能够看懂别人写的代码,
并能够正确的调用。
编号 房主 电话 地址 月租 状态(未出租/已出租
9.4.3项目功能实现-显示主菜单和完成退出软件功能
老师说明:实现功能的三部曲 [明确完成功能->思路分析->代码实现]
功能说明:
用户打开软件, 可以看到主菜单,可以退出软件.
思路分析:
在 HouseView.java 中,编写一个方法 mainMenu,显示菜单.
代码实现:
9.4.4项目功能实现-完成显示房屋列表的功能
9.4.5项目功能实现-添加房屋信息的功能
9.4.6项目功能实现-完成删除房屋信息的功能
9.4.7项目功能实现-完善退出确认功能 (课堂作业)
9.4.8项目功能实现-完成根据 id 查找房屋信息的功能 (课后作业)
9.4.9项目功能实现-完成修改房屋信息的功能 (课后作业)
第 10 章面向对象编程(高级部分)
10. 1 类变量和类方法
10. 1. 1 类变量-提出问题
提出问题的主要目的就是让大家思考解决之道,从而引出我要讲的知识点.
说:有一群小孩在玩堆雪人,不时有新的小孩加入,请问如何知道现在共有多少人在玩? ,编写程序解决。
1.2 传统的方法来解决
1.3 类变量快速入门
思考: 如果,设计一个 int count 表示总人数,我们在创建一个小孩时,就把 count 加 1,并且 count 是所有对象共享的 就 ok 了! ,我们使用类变量来解决 ChildGame.java 改进
代码.
package com.hspedu.static_;
public class ChildGame {
public static void main(String[] args) {
//定义一个变量 count, 统计有多少小孩加入了游戏
int count = 0;
Child child1 = new Child(“白骨精”);
child1.join();
//count++;
child1.count++;
Child child2 = new Child(“狐狸精”);
child2.join();
//count++;
child2.count++;
Child child3 = new Child(“老鼠精”);
child3.join();
//count++;
child3.count++;
//===========
//类变量,可以通过类名来访问
System.out.println(“共有” + Child.count + " 小孩加入了游戏…");
//下面的代码输出什么?
System.out.println(“child1.count=” + child1.count);//3
System.out.println(“child2.count=” + child2.count);//3
System.out.println(“child3.count=” + child3.count);//3
}
}
class Child { //类
private String name;
//定义一个变量 count ,是一个类变量(静态变量) static 静态
//该变量最大的特点就是会被 Child 类的所有的对象实例共享
public static int count = 0;
public Child(String name) {
this.name = name;
}
public void join() {
System.out.println(name + " 加入了游戏…");
}
}
10. 1.4 类变量内存布局
1.5 什么是类变量
1.6 如何定义类变量
1.7 如何访问类变量 VisitStatic.java
代码
package com.hspedu.static_;
public class VisitStatic {
public static void main(String[] args) {
//类名.类变量名
//说明:类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问
System.out.println(A.name);
A a = new A();
//通过对象名.类变量名
System.out.println(“a.name=” + a.name);
}
}
class A {
//类变量
//类变量的访问,必须遵守 相关的访问权限.
public static String name = “韩顺平教育”;
//普通属性/普通成员变量/非静态属性/非静态成员变量/实例变量
private int num = 10;
}
10. 1.8 类变量使用注意事项和细节讨论 StaticDetail.java
代码:
package com.hspedu.static_;
public class StaticDetail {
public static void main(String[] args) {
B b = new B();
//System.out.println(B.n1);
System.out.println(B.n2);
//静态变量是类加载的时候,就创建了,所以我们没有创建对象实例
//也可以通过类名.类变量名来访问
System.out.println(C.address);
}
}
class B {
public int n1 = 100;
public static int n2 = 200;
}
class C {
public static String address = “北京”;
}
10. 1.9 类方法基本介绍
package com.hspedu.static_;
public class StaticMethod {
public static void main(String[] args) {
//创建 2 个学生对象,叫学费
Stu tom = new Stu(“tom”);
//tom.payFee( 100);
Stu.payFee( 100);//对不对?对
Stu mary = new Stu(“mary”);
//mary.payFee(200);
Stu.payFee(200);//对
//输出当前收到的总学费
Stu.showFee();//300
//如果我们希望不创建实例,也可以调用某个方法(即当做工具来使用)
//这时,把方法做成静态方法时非常合适
System.out.println(“9 开平方的结果是=” + Math.sqrt(9));
System.out.println(MyTools.calSum( 10, 30));
}
}
//开发自己的工具类时,可以将方法做成静态的,方便调用
class MyTools {
//求出两个数的和
public static double calSum(double n1, double n2) {
return n1 + n2;
}
//可以写出很多这样的工具方法…
}
class Stu {
private String name;//普通成员
//定义一个静态变量,来累积学生的学费
private static double fee = 0;
public Stu(String name) {
this.name = name;
}
//说明
//1. 当方法使用了 static 修饰后,该方法就是静态方法
//2. 静态方法就可以访问静态属性/变量
public static void payFee(double fee) {
Stu.fee += fee;//累积到
}
public static void showFee() {
System.out.println(“总学费有:” + Stu.fee);
}
}
10. 1. 12 类方法经典的使用场景
代码:
package com.hspedu.static_;
public class StaticMethodDetail {
public static void main(String[] args) {
D.hi();//ok
//非静态方法,不能通过类名调用
//D.say();, 错误,需要先创建对象,再调用
new D().say();//可以
}
}
class D {
private int n1 = 100;
private static int n2 = 200;
public void say() {//非静态方法,普通方法
}
public static void hi() {//静态方法,类方法
//类方法中不允许使用和对象有关的关键字,
//比如 this 和 super 。普通方法(成员方法)可以。
//System.out.println(this.n1);
}
//类方法(静态方法)中 只能访问 静态变量 或静态方法
//口诀:静态方法只能访问静态成员.
public static void hello() {
System.out.println(n2);
System.out.println(D.n2);
//System.out.println(this.n2);不能使用
hi();//OK
//say();//错误
}
//普通成员方法,既可以访问 非静态成员,也可以访问静态成员
//小结: 非静态方法可以访问 静态成员和非静态成员
public void ok() {
//非静态成员
System.out.println(n1);
say();
//静态成员
System.out.println(n2);
hello();
}
}
class Person { //StaticExercise02.java 2min 时间
private int id;
private static int total = 0;
public static int getTotalPerson() {
//id++;//错误, 注销
return total;
}
public Person() {//构造器
total++; //total = 1
id = total;//id = 1
}
}
public class TestPerson {
public static void main(String[] args) {
System.out.println("Number of total is " +Person.getTotalPerson()); //0
Person p1 = new Person();
System.out.println( "Number of total is "+ Person.getTotalPerson()); //1
}
}
10. 1. 16 题 3(评讲) ,看看下面代码有没有错误,如果有错误,就修改,看看 total 等于多少 4?
代码:
class Person { //StaticExercise03.java 2min 看
private int id;
private static int total = 0;
public static void setTotalPerson(int total){
// this.total = total;//错误,因为在 static 方法中,不可以使用 this 关键字
Person.total = total;
}
public Person() {//构造器
total++;
id = total;
}}
public class TestPerson {
public static void main(String[] args) {
Person.setTotalPerson(3);
new Person(); //最后 total 的值就是 4
}
}
小结:记住两句话 ( 1) 静态方法,只能访问静态成员 (2) 非静态方法,可以访问所有的成员
(3) 在编写代码时,仍然要遵守访问权限规则
10.2 理解 main 方法语法
10.2. 1 深入理解 main 方法
10.2.2 特别提示:
package com.hspedu.main_;
public class Main01 {
//静态的变量/属性
private static String name = “韩顺平教育”;
//非静态的变量/属性
private int n1 = 10000;
//静态方法
public static void hi() {
System.out.println(“Main01 的 hi 方法”);
}
//非静态方法
public void cry() {
System.out.println(“Main01 的 cry 方法”);
}
public static void main(String[] args) {
//可以直接使用 name
//1. 静态方法 main 可以访问本类的静态成员
System.out.println(“name=” + name);
hi();
//2. 静态方法 main 不可以访问本类的非静态成员
//System.out.println(“n1=” + n1);//错误
//cry();
//3. 静态方法 main 要访问本类的非静态成员,需要先创建对象 , 再调用即可
Main01 main01 = new Main01();
System.out.println(main01.n1);//ok
main01.cry();
}
}
10.2.3 案例演示
10.3 代码块
10.3. 1 基本介绍
10.3.2 基本语法
10.3.3 代码块的好处和案例演示
代码:
package com.hspedu.codeblock_;
public class CodeBlock01 {
public static void main(String[] args) {
Movie movie = new Movie(“你好,李焕英”);
System.out.println(“===============”);
Movie movie2 = new Movie(“唐探 3”, 100, “陈思诚”);
}
}
class Movie {
private String name;
private double price;
private String director;
//3 个构造器- 》重载
//老韩解读
//(1) 下面的三个构造器都有相同的语句
//(2) 这样代码看起来比较冗余
//(3) 这时我们可以把相同的语句,放入到一个代码块中,即可
//(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容
//(5) 代码块调用的顺序优先于构造器…
{
System.out.println(“电影屏幕打开…”);
System.out.println(“广告开始…”);
System.out.println(“电影正是开始…”);
};
public Movie(String name) {
System.out.println(“Movie(String name) 被调用…”);
this.name = name;
}
public Movie(String name, double price) {
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
System.out.println(“Movie(String name, double price, String director) 被调用…”);
this.name = name;
this.price = price;
this.director = director;
}
}
10.3.4 代码块使用注意事项和细节讨论 CodeBlockDetail01.java
代码:
package com.hspedu.codeblock_;
public class CodeBlockDetail01 {
public static void main(String[] args) {
//类被加载的情况举例
//1. 创建对象实例时(new)
// AA aa = new AA();
//2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载
// AA aa2 = new AA();
//3. 使用类的静态成员时(静态属性,静态方法)
// System.out.println(Cat.n1);
//static 代码块,是在类加载时,执行的,而且只会执行一次.
//
//
}
} DD dd = new DD();
DD dd1 = new DD();
//普通的代码块,在创建对象实例时,会被隐式的调用。
// 被创建一次,就会调用一次。
// 如果只是使用类的静态成员时,普通代码块并不会执行
System.out.println(DD.n1);//8888, 静态模块块一定会执行
class DD {
public static int n1 = 8888;//静态属性
//静态代码块
static {
System.out.println(“DD 的静态代码 1 被执行…”);//
}
//普通代码块, 在 new 对象时,被调用,而且是每创建一个对象,就调用一次
//可以这样简单的,理解 普通代码块是构造器的补充
{
System.out.println(“DD 的普通代码块…”);
}
}
class Animal {
//静态代码块
static {
System.out.println(“Animal 的静态代码 1 被执行…”);//
}
}
class Cat extends Animal {
public static int n1 = 999;//静态属性
//静态代码块
static {
System.out.println(“Cat 的静态代码 1 被执行…”);//
}
}
class BB {
//静态代码块
static {
System.out.println(“BB 的静态代码 1 被执行…”);//1
}
}
class AA extends BB {
//静态代码块
static {
System.out.println(“AA 的静态代码 1 被执行…”);//2
}
}
代码:
package com.hspedu.codeblock_;
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();// (1) A 静态代码块 01 (2) getN1 被调用…(3)A 普通代码块 01(4)getN2 被调用…(5)A() 构造器被调 用
}
}
class A {
{ //普通代码块
System.out.println(“A 普通代码块 01”);
}
private int n2 = getN2();//普通属性的初始化
static { //静态代码块
System.out.println(“A 静态代码块 01”);
}
//静态属性的初始化
private static int n1 = getN1();
public static int getN1() {
System.out.println(“getN1 被调用…”);
return 100;
}
public int getN2() { //普通方法/非静态方法
System.out.println(“getN2 被调用…”);
return 200;
}
//无参构造器
public A() {
System.out.println(“A() 构造器被调用”);
}
}
代码
package com.hspedu.codeblock_;
public class CodeBlockDetail03 {
public static void main(String[] args) {
new BBB();//(1)AAA 的普通代码块(2)AAA() 构造器被调用(3)BBB 的普通代码块(4)BBB() 构造器被调用 }
}
class AAA { //父类 Object
{
System.out.println(“AAA 的普通代码块”);
}
public AAA() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println(“AAA() 构造器被调用…”);
}
}
class BBB extends AAA {
{
System.out.println(“BBB 的普通代码块…”);
}
public BBB() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println(“BBB() 构造器被调用…”);
}
}
代码:
package com.hspedu.codeblock_;
public class CodeBlockDetail04 {
public static void main(String[] args) {
//老师说明
//(1) 进行类的加载
//1. 1 先加载 父类 A02 1.2 再加载 B02
//(2) 创建对象
//2. 1 从子类的构造器开始
//new B02();//对象
new C02();
}
}
class A02 { //父类
private static int n1 = getVal01();
static {
System.out.println(“A02 的一个静态代码块…”);//(2)
}
{
System.out.println(“A02 的第一个普通代码块…”);//(5)
}
public int n3 = getVal02();//普通属性的初始化
public static int getVal01() {
System.out.println(“getVal01”);//(1)
return 10;
}
public int getVal02() {
System.out.println(“getVal02”);//(6)
return 10;
}
public A02() {//构造器
//隐藏
//super()
//普通代码和普通属性的初始化…
System.out.println(“A02 的构造器”);//(7)
}
}
class C02 {
private int n1 = 100;
private static int n2 = 200;
private void m1() {
}
private static void m2() {
}
static {
//静态代码块,只能调用静态成员
//System.out.println(n1);错误
System.out.println(n2);//ok
//m1();//错误
m2();
}
{
//普通代码块,可以使用任意成员
System.out.println(n1);
System.out.println(n2);//ok
m1();
m2();
}
}
class B02 extends A02 { //
private static int n3 = getVal03();
static {
System.out.println(“B02 的一个静态代码块…”);//(4)
}
public int n5 = getVal04();
{
System.out.println(“B02 的第一个普通代码块…”);//(9)
}
public static int getVal03() {
System.out.println(“getVal03”);//(3)
return 10;
}
public int getVal04() {
System.out.println(“getVal04”);//(8)
return 10;
}
//一定要慢慢的去品…
public B02() {//构造器
//隐藏了
//super()
//普通代码块和普通属性的初始化…
System.out.println(“B02 的构造器”);//(10)
// TODO Auto-generated constructor stub
}
}
10.3.5 课堂练习题 CodeBlockExercise01.java
题 1 :下面的代码输出什么?1min
class Person {
public static int total;//静态变量
static {//静态代码块
total = 100;
System.out.println(“in static block!”);//(1)
}
}
public class Test {
public static void main(String[] args) {
System.out.println("total = "+ Person.total); //100
System.out.println("total = "+ Person.total); //100
}
}
10.3.6 题 2:下面的代码输出什么?
题 2 :下面的代码输出什么?CodeBlockExercise02.java
class Sample
{
Sample(String s)
{
System.out.println(s);
}
Sample()
{
System.out.println(“Sample 默认构造函数被调用");
}
}
//====
class Test{
Sample sam1=new Sample(“sam1 成员初始化”);//
static Sample sam=new Sample("静态成员 sam 初始化 ");//
static {
System.out.println(“static 块执行”);//
if(sam==null)System.out.println(“sam is null”);
}
Test()//构造器
{
System.out.println(“Test 默认构造函数被调用”);//
}
}
//主方法
public static void main(String str[])
{
Test a=new Test();//无参构造器
}
//运行结果, 输出什么内容,并写出. 2min 看看
10.4 单例设计模式
10.4. 1 什么是设计模式
10.4.2 什么是单例模式
10.4.3 单例模式应用实例
代码:
package com.hspedu.single_;
public class SingleTon01 {
public static void main(String[] args) {
// GirlFriend xh = new GirlFriend(“小红”);
// GirlFriend xb = new GirlFriend(“小白”);
//通过方法可以获取对象
GirlFriend instance = GirlFriend.getInstance();
System.out.println(instance);
GirlFriend instance2 = GirlFriend.getInstance();
System.out.println(instance2);
System.out.println(instance == instance2);//T
//System.out.println(GirlFriend.n1);
//…
}
}
//有一个类, GirlFriend
//只能有一个女朋友
class GirlFriend {
private String name;
//public static int n1 = 100;
//为了能够在静态方法中,返回 gf 对象,需要将其修饰为 static
//對象,通常是重量級的對象, 餓漢式可能造成創建了對象,但是沒有使用.
private static GirlFriend gf = new GirlFriend(“小红红”);
//如何保障我们只能创建一个 GirlFriend 对象
//步骤[单例模式-饿汉式]
//1. 将构造器私有化
//2. 在类的内部直接创建对象(该对象是 static)
//3. 提供一个公共的 static 方法,返回 gf 对象
private GirlFriend(String name) {
System.out.println(“構造器被調用.”);
this.name = name;
}
public static GirlFriend getInstance() {
return gf;
}
@Override
public String toString() {
return “GirlFriend{” +
“name='” + name + ‘’’ +
‘}’;
}
}
package com.hspedu.single_;
/**
//再次調用 getInstance
Cat instance2 = Cat.getInstance();
System.out.println(instance2);
System.out.println(instance == instance2);//T
}
}
//希望在程序運行過程中,只能創建一個 Cat 對象
//使用單例模式
class Cat {
private String name;
public static int n1 = 999;
private static Cat cat ; //默認是 null
//步驟
//1.仍然構造器私有化
//2.定義一個 static 靜態屬性對象
//3.提供一個 public 的 static 方法,可以返回一個 Cat 對象
//4.懶漢式,只有當用戶使用 getInstance 時,才返回 cat 對象, 後面再次調用時,會返回上次創建的 cat 對象 // 從而保證了單例
private Cat(String name) {
System.out.println(“構造器調用…”);
this.name = name;
}
public static Cat getInstance() {
if(cat == null) {//如果還沒有創建 cat 對象
cat = new Cat(“小可愛”);
}
return cat;
}
@Override
public String toString() {
return “Cat{” +
“name='” + name + ‘’’ +
‘}’;
}
}
10.4.4 饿汉式 VS 懒汉式
10.5 final 关键字
10.5. 1 基本介绍
代码:
package com.hspedu.final_;
public class Final01 {
public static void main(String[] args) {
E e = new E();
//e.TAX_RATE = 0.09;
}
}
//如果我们要求 A 类不能被其他类继承
//可以使用 final 修饰 A 类
final class A { }
//class B extends A {}
class C {
//如果我们要求 hi 不能被子类重写
//可以使用 final 修饰 hi 方法
public final void hi() {}
}
class D extends C {
// @Override
// public void hi() {
// System.out.println(“重写了 C 类的 hi 方法…”);
// }
}
//当不希望类的的某个属性的值被修改,可以用final 修饰
class E {
public final double TAX_RATE = 0.08;//常量
}
//当不希望某个局部变量被修改,可以使用final 修饰
class F {
public void cry() {
//这时,NUM 也称为 局部常量
final double NUM = 0.01;
//NUM = 0.9;
System.out.println(“NUM=” + NUM);
}
}
10.5.2 final 使用注意事项和细节讨论
代码:
package com.hspedu.final_;
public class FinalDetail01 {
public static void main(String[] args) {
CC cc = new CC();
new EE().cal();
}
}
class AA {
/*
public AA() {//构造器中赋值
TAX_RATE2 = 1. 1;
}
{//在代码块赋值
TAX_RATE3 = 8.8;
}
}
class BB {
/*
如果 final 修饰的属性是静态的,则初始化的位置只能是
1 定义时 2 在静态代码块 不能在构造器中赋值。 */
public static final double TAX_RATE = 99.9;
public static final double TAX_RATE2 ;
static {
TAX_RATE2 = 3.3;
}
}
//final 类不能继承,但是可以实例化对象
final class CC { }
//如果类不是 final 类,但是含有 final 方法,则该方法虽然不能重写,但是可以被继承
//即,仍然遵守继承的机制.
class DD {
public final void cal() {
System.out.println(“cal()方法”);
}
}
class EE extends DD { }
代码:
package com.hspedu.final_;
public class FinalDetail02 {
public static void main(String[] args) {
System.out.println(BBB.num);
//包装类,String 是 final 类,不能被继承
}
}
//final 和 static 往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理
class BBB {
public final static int num = 10000;
static {
System.out.println(“BBB 静态代码块被执行”);
}
}
final class AAA{
//一般来说,如果一个类已经是 final 类了,就没有必要再将方法修饰成 final 方法
//public final void cry() {}
}
10.5.3 final 应用实例
代码:
package com.hspedu.final_;
public class FinalExercise01 {
public static void main(String[] args) {
Circle circle = new Circle(5.0);
System.out.println(“面积=” + circle.calArea());
}
}
class Circle {
private double radius;
private final double PI;// = 3. 14;
//构造器
public Circle(double radius) {
this.radius = radius;
//PI = 3. 14;
}
{
PI = 3. 14;
}
public double calArea() {
return PI * radius * radius;
}
}
题 2
public int addOne(final int x) { //下面的代码是否有误,为什么? 1min
++x; //错误,原因是不能修改 final x 的值
return x + 1; //这里是可以.
}
}
10.6 抽象类
10.6. 1 先看一个问题 Abstract01.java
代码:
package com.hspedu.abstract_;
public class Abstract01 {
public static void main(String[] args) {
}
}
abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
//思考:这里 eat 这里你实现了,其实没有什么意义
//即: 父类方法不确定性的问题
//=> 考虑将该方法设计为抽象(abstract)方法
//=> 所谓抽象方法就是没有实现的方法
//=> 所谓没有实现就是指,没有方法体
//=> 当一个类中存在抽象方法时,需要将该类声明为 abstract 类
//===> 一般来说,抽象类会被继承,有其子类来实现抽象方法.
// public void eat() {
// System.out.println(“这是一个动物,但是不知道吃什么…”);
// }
public abstract void eat() ;
}
10.6.2 解决之道-抽象类快速入门
10.6.3 抽象类的介绍
10.6.4 抽象类使用的注意事项和细节讨论 AbstractDetail01.java
代码:
package com.hspedu.abstract_;
public class AbstractDetail01 {
public static void main(String[] args) {
//抽象类,不能被实例化
//new A();
}
}
//抽象类不一定要包含 abstract 方法。也就是说,抽象类可以没有 abstract 方法
// ,还可以有实现的方法。
abstract class A {
public void hi() {
System.out.println(“hi”);
}
}
//一旦类包含了 abstract 方法,则这个类必须声明为 abstract
abstract class B {
public abstract void hi();
}
//abstract 只能修饰类和方法,不能修饰属性和其它的
class C {
// public abstract int n1 = 1;
}
10.6.5 抽象类使用的注意事项和细节讨论 AbstractDetail02.java
代码:
package com.hspedu.abstract_;
public class AbstractDetail02 {
public static void main(String[] args) {
System.out.println(“hello”);
}
}
//抽象方法不能使用 private 、final 和 static 来修饰,因为这些关键字都是和重写相违背的
abstract class H {
public abstract void hi();//抽象方法
}
//如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为 abstract 类 abstract class E {
public abstract void hi();
}
abstract class F extends E {
}
class G extends E {
@Override
public void hi() { //这里相等于 G 子类实现了父类 E 的抽象方法,所谓实现方法,就是有方法体
}
}
//抽象类的本质还是类,所以可以有类的各种成员
abstract class D {
public int n1 = 10;
public static String name = “韩顺平教育”;
public void hi() {
System.out.println(“hi”);
}
public abstract void hello();
public static void ok() {
System.out.println(“ok”);
}
}
10.6.6 课堂练习题 AbstractExercise01.java 5min 练习
代码:
package com.hspedu.abstract_;
public class AbstractExercise01 {
public static void main(String[] args) {
//测试
Manager jack = new Manager(“jack”, 999, 50000);
jack.setBonus(8000);
jack.work();
CommonEmployee tom = new CommonEmployee(“tom”, 888, 20000);
tom.work();
}
}
package com.hspedu.abstract_;
abstract public class Employee {
private String name;
private int id;
private double salary;
public Employee(String name, int id, double salary) {
this.name = name;
this.id = id;
this.salary = salary;
}
//将 work 做成一个抽象方法
public abstract void work();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.hspedu.abstract_;
public class Manager extends Employee {
private double bonus;
public Manager(String name, int id, double salary) {
super(name, id, salary);
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public void work() {
System.out.println(“经理 " + getName() + " 工作中…”);
}
}
package com.hspedu.abstract_;
public class CommonEmployee extends Employee{
public CommonEmployee(String name, int id, double salary) {
super(name, id, salary);
}
@Override
public void work() {
System.out.println(“普通员工 " + getName() + " 工作中…”);
}
}
10.7 抽象类最佳实践-模板设计模式
10.7. 1 基本介绍
10.7.2 模板设计模式能解决的问题
10.7.3 最佳实践
代码:
package com.hspedu.abstract_;
abstract public class Template { //抽象类-模板设计模式
public abstract void job();//抽象方法
public void calculateTime() {//实现方法,调用job 方法
//得到开始的时间
long start = System.currentTimeMillis();
job(); //动态绑定机制
//得的结束的时间
long end = System.currentTimeMillis();
System.out.println("任务执行时间 " + (end - start));
}
}
package com.hspedu.abstract_;
public class AA extends Template {
//计算任务
//1+…+ 800000
@Override
public void job() { //实现 Template 的抽象方法job
long num = 0;
for (long i = 1; i <= 800000; i++) {
num += i;
}
}
// public void job2() {
// //得到开始的时间
// long start = System.currentTimeMillis();
// long num = 0;
//
//
//
//
//
//
//
}
} for (long i = 1; i <= 200000; i++) {
num += i;
}
//得的结束的时间
long end = System.currentTimeMillis();
System.out.println("AA 执行时间 " + (end - start));
package com.hspedu.abstract_;
public class BB extends Template {
public void job() {//这里也去,重写了 Template 的job 方法
long num = 0;
for (long i = 1; i <= 80000; i++) {
num *= i;
}
}
}
package com.hspedu.abstract_;
public class TestTemplate {
public static void main(String[] args) {
AA aa = new AA();
aa.calculateTime(); //这里还是需要有良好的 OOP 基础,对多态
BB bb = new BB();
bb.calculateTime();
}
}
10.8 接口
10.8. 1 为什么有接口
10.8.2 接口快速入门
代码:
package com.hspedu.interface_;
public interface UsbInterface { //接口
//规定接口的相关方法,老师规定的. 即规范…
public void start();
public void stop();
}
package com.hspedu.interface_;
public class Camera implements UsbInterface {//实现接口,就是把接口方法实现
@Override
public void start() {
System.out.println(“相机开始工作…”);
}
@Override
public void stop() {
System.out.println(“相机停止工作…”);
}
}
package com.hspedu.interface_;
//Phone 类 实现 UsbInterface
//解读 1. 即 Phone 类需要实现 UsbInterface 接口 规定/声明的方法
public class Phone implements UsbInterface {
@Override
public void start() {
System.out.println(“手机开始工作…”);
}
@Override
public void stop() {
System.out.println(“手机停止工作…”);
}
}
package com.hspedu.interface_;
public class Interface01 {
public static void main(String[] args) {
//创建手机,相机对象
//Camera 实现了 UsbInterface
Camera camera = new Camera();
//Phone 实现了 UsbInterface
Phone phone = new Phone();
//创建计算机
Computer computer = new Computer();
computer.work(phone);//把手机接入到计算机
System.out.println(“===============”);
computer.work(camera);//把相机接入到计算机
}
}
10.8.3 基本介绍
10.8.4 深入讨论
代码:
package com.hspedu.interface_;
public interface DBInterface { //项目经理
public void connect();//连接方法
public void close();//关闭连接
}
package com.hspedu.interface_;
//A 程序
public class MysqlDB implements DBInterface {
@Override
public void connect() {
System.out.println(“连接 mysql”);
}
@Override
public void close() {
System.out.println(“关闭 mysql”);
}
}
package com.hspedu.interface_;
//B 程序员连接 Oracle
public class OracleDB implements DBInterface {
@Override
public void connect() {
System.out.println(“连接 oracle”);
}
@Override
public void close() {
System.out.println(“关闭 oracle”);
}
}
package com.hspedu.interface_;
public class Interface03 {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
t(mysqlDB);
OracleDB oracleDB = new OracleDB();
t(oracleDB);
}
public static void t(DBInterface db) {
db.connect();
db.close();
}
}
10.8.5 注意事项和细节
代码:
package com.hspedu.interface_;
public class InterfaceDetail01 {
public static void main(String[] args) {
//new IA();
}
}
//1.接口不能被实例化
//2.接口中所有的方法是 public 方法, 接口中抽象方法,可以不用 abstract 修饰
//3.一个普通类实现接口,就必须将该接口的所有方法都实现,可以使用 alt+enter 来解决
//4.抽象类去实现接口时,可以不实现接口的抽象方法
interface IA {
void say();//修饰符 public protected 默认 private
void hi();
}
class Cat implements IA{
@Override
public void say() {
}
@Override
public void hi() {
}
}
abstract class Tiger implements IA {
}
代码
package com.hspedu.interface_;
public class InterfaceDetail02 {
public static void main(String[] args) {
//老韩证明 接口中的属性,是 public static final
System.out.println(IB.n1);//说明 n1 就是 static
//IB.n1 = 30; 说明 n1 是 final
}
}
interface IB {
//接口中的属性, 只能是 final 的,而且是 public static final 修饰符
int n1 = 10; //等价 public static final int n1 = 10;
void hi();
}
interface IC {
void say();
}
//接口不能继承其它的类,但是可以继承多个别的接口
interface ID extends IB,IC {
}
//接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的
interface IE{}
//一个类同时可以实现多个接口
class Pig implements IB,IC {
@Override
public void hi() {
}
@Override
public void say() {
}
}
10.8.6 课堂练习
10.8.7 实现接口 vs 继承类
代码:
package com.hspedu.interface_;
public class ExtendsVsInterface {
public static void main(String[] args) {
LittleMonkey wuKong = new LittleMonkey(“悟空”);
wuKong.climbing();
wuKong.swimming();
wuKong.flying();
}
}
//猴子
class Monkey {
private String name;
public Monkey(String name) {
this.name = name;
}
public void climbing() {
System.out.println(name + " 会爬树…");
}
public String getName() {
return name;
}
}
//接口
interface Fishable {
void swimming();
}
interface Birdable {
void flying();
}
//继承
//小结: 当子类继承了父类,就自动的拥有父类的功能
//
// 如果子类需要扩展功能,可以通过实现接口的方式扩展.
可以理解 实现接口 是 对java 单继承机制的一种补充.
class LittleMonkey extends Monkey implements Fishable,Birdable {
public LittleMonkey(String name) {
super(name);
}
@Override
public void swimming() {
System.out.println(getName() + " 通过学习,可以像鱼儿一样游泳…");
}
@Override
public void flying() {
System.out.println(getName() + " 通过学习,可以像鸟儿一样飞翔…");
}
}
10.8.8 接口的多态特性
代码:
package com.hspedu.interface_;
public class InterfacePolyParameter {
public static void main(String[] args) {
//接口的多态体现
//接口类型的变量 if01 可以指向 实现了IF 接口类的对象实例
IF if01 = new Monster();
if01 = new Car();
//继承体现的多态
//父类类型的变量 a 可以指向 继承 AAA 的子类的对象实例
AAA a = new BBB();
a = new CCC();
}
}
interface IF {}
class Monster implements IF{}
class Car implements IF{}
class AAA {
}
class BBB extends AAA {}
class CCC extends AAA {}
package com.hspedu.interface_;
public class InterfacePolyArr {
public static void main(String[] args) {
//多态数组 -> 接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Phone_();
usbs[ 1] = new Camera_();
/*
给 Usb 数组中,存放 Phone 和 相机对象,Phone 类还有一个特有的方法 call () ,
请遍历 Usb 数组,如果是 Phone 对象,除了调用 Usb 接口定义的方法外,
还需要调用 Phone 特有方法 call
*/
for(int i = 0; i < usbs.length; i++) {
usbs[i].work();//动态绑定…
//和前面一样,我们仍然需要进行类型的向下转型
if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
((Phone_) usbs[i]).call();
}
}
}
}
interface Usb{
void work();
}
class Phone_ implements Usb {
public void call() {
System.out.println(“手机可以打电话…”);
}
@Override
public void work() {
System.out.println(“手机工作中…”);
}
}
class Camera_ implements Usb {
@Override
public void work() {
System.out.println(“相机工作中…”);
}
}
package com.hspedu.interface_;
/**
interface IH {
void hi();
}
interface IG extends IH{ }
class Teacher implements IG {
@Override
public void hi() {
}
}
10.8.9 课堂练习 InterfaceExercise02.java
package com.hspedu.interface_;
public class InterfaceExercise02 {
public static void main(String[] args) {
}
}
interface A { // 1min 看看
int x = 0;
} //想到 等价 public static final int x = 0;
class B {
int x = 1;
} //普通属性
class C extends B implements A {
public void pX() {
//System.out.println(x); //错误,原因不明确 x
//可以明确的指定 x
//访问接口的 x 就使用 A.x
//访问父类的 x 就使用 super.x
System.out.println(A.x + " " + super.x);
}
public static void main(String[] args) {
new C().pX();
}
}
10.9 内部类
如果定义类在局部位置(方法中/代码块) 1) 局部内部类 (2) 匿名内部类
定义在成员位置 ( 1) 成员内部类 (2) 静态内部类
10.9. 1 基本介绍
10.9.2 基本语法
10.9.3 快速入门案例
代码:
package com.hspedu.innerclass;
public class InnerClass01 { //外部其他类
public static void main(String[] args) {
}
}
class Outer { //外部类
private int n1 = 100;//属性
public Outer(int n1) {//构造器
this.n1 = n1;
}
public void m1() {//方法
System.out.println(“m1()”);
}
{//代码块
System.out.println(“代码块…”);
}
class Inner { //内部类, 在 Outer 类的内部
}
}
10.9.4 内部类的分类
10.9.5 局部内部类的使用 LocalInnerClass.java
代码:
package com.hspedu.innerclass;
/**
class Outer02 {//外部类
private int n1 = 100;
private void m2() {
System.out.println(“Outer02 m2()”);
}//私有方法
public void m1() {//方法
//1.局部内部类是定义在外部类的局部位置,通常在方法
//3.不能添加访问修饰符,但是可以使用 final 修饰
//4.作用域 : 仅仅在定义它的方法或代码块中
final class Inner02 {//局部内部类(本质仍然是一个类)
//2.可以直接访问外部类的所有成员,包含私有的
private int n1 = 800;
public void f1() {
//5. 局部内部类可以直接访问外部类的成员,比如下面 外部类 n1 和 m2()
//7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员, // 使用 外部类名.this.成员) 去访问
// 老韩解读 Outer02.this 本质就是外部类的对象, 即哪个对象调用了 m1, Outer02.this 就是哪个对象 System.out.println(“n1=” + n1 + " 外部类的 n1=" + Outer02.this.n1);
System.out.println(“Outer02.this hashcode=” + Outer02.this);
m2();
}
}
//6. 外部类在方法中,可以创建 Inner02 对象,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
}
10.9.6 匿名内部类的使用(重要!!!)
代码:
package com.hspedu.innerclass;
/**
class Outer04 { //外部类
private int n1 = 10;//属性
public void method() {//方法
//基于接口的匿名内部类
//老韩解读
//1.需求: 想使用 IA 接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
//3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
//4. 可以使用匿名内部类来简化开发
//5. tiger 的编译类型 ? IA
//6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
/*
我们看底层 会分配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println(“老虎叫唤…”);
}
}
*/
//7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址 // 返回给 tiger
//8. 匿名内部类使用一次,就不能再使用
IA tiger = new IA() {
@Override
public void cry() {
System.out.println(“老虎叫唤…”);
}
};
System.out.println(“tiger 的运行类型=” + tiger.getClass());
tiger.cry();
tiger.cry();
//
// tiger.cry();
IA tiger = new Tiger();
tiger.cry();
//演示基于类的匿名内部类
//分析
//1. father 编译类型 Father
//2. father 运行类型 Outer04$2
//3. 底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println(“匿名内部类重写了 test 方法”);
}
}
*/
//4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
//5. 注意(“jack”) 参数列表会传递给 构造器
Father father = new Father(“jack”){
@Override
public void test() {
System.out.println(“匿名内部类重写了 test 方法”);
}
};
System.out.println(“father 对象的运行类型=” + father.getClass());//Outer04$2
father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println(“小狗吃骨头…”);
}
};
animal.eat();
}
}
interface IA {//接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println(“老虎叫唤…”);
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println(“小狗汪汪…”);
// }
//}
class Father {//类
public Father(String name) {//构造器
System.out.println(“接收到 name=” + name);
}
public void test() {//方法
}
}
abstract class Animal { //抽象类
abstract void eat();
}
代码:
package com.hspedu.innerclass;
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
//外部其他类—不能访问----->匿名内部类
System.out.println(“main outer05 hashcode=” + outer05);
}
}
class Outer05 {
private int n1 = 99;
public void f1() {
//创建一个基于类的匿名内部类
//不能添加访问修饰符, 因为它的地位就是一个局部变量
//作用域 : 仅仅在定义它的方法或代码块中
Person p = new Person(){
private int n1 = 88;
@Override
public void hi() {
//可以直接访问外部类的所有成员,包含私有的
//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,
//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员) 去访问 System.out.println(“匿名内部类重写了 hi 方法 n1=” + n1 +
" 外部内的 n1=" + Outer05.this.n1 );
//Outer05.this 就是调用 f1 的 对象
System.out.println(“Outer05.this hashcode=” + Outer05.this);
}
};
p.hi();//动态绑定, 运行类型是 Outer05$1
//也可以直接调用, 匿名内部类本身也是返回对象
// class 匿名内部类 extends Person {}
//
//
//
//
//
//
//
//
//
// new Person(){
@Override
public void hi() {
System.out.println(“匿名内部类重写了 hi 方法,哈哈…”);
}
@Override
public void ok(String str) {
super.ok(str);
}
}.ok(“jack”);
}
}
class Person {//类
public void hi() {
System.out.println(“Person hi()”);
}
public void ok(String str) {
System.out.println("Person ok() " + str);
}
}
//抽象类/接口…
10.9.7 匿名内部类的最佳实践
当做实参直接传递,简洁高效。 InnerClassExercise01.java
package com.hspedu.innerclass;
import com.hspedu.abstract_.AA;
public class InnerClassExercise01 {
public static void main(String[] args) {
//当做实参直接传递,简洁高效
f1(new IL() {
@Override
public void show() {
System.out.println(“这是一副名画~~…”);
}
});
//传统方法
f1(new Picture());
}
//静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
//接口
interface IL {
void show();
}
//类->实现 IL => 编程领域 (硬编码)
class Picture implements IL {
@Override
public void show() {
System.out.println(“这是一副名画 XX…”);
}
}
10.9.8 匿名内部类课堂练习
代码:
package com.hspedu.innerclass;
public class InnerClassExercise02 {
public static void main(String[] args) {
/*
1.有一个铃声接口 Bell ,里面有个 ring 方法。(右图)
2.有一个手机类 Cellphone ,具有闹钟功能 alarmClock ,参数是 Bell 类型(右图)
3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
4.再传入另一个匿名内部类(对象) ,打印:小伙伴上课了
*/
CellPhone cellPhone = new CellPhone();
//老韩解读
//1. 传递的是实现了 Bell 接口的匿名内部类 InnerClassExercise02$1
//2. 重写了 ring
//3. Bell bell = new Bell() {
//
// @Override
public void ring() {
//
//
// System.out.println(“懒猪起床了”);
}
}
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println(“懒猪起床了”);
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println(“小伙伴上课了”);
}
});
}
}
interface Bell{ //接口
void ring();//方法
}
class CellPhone{//类
public void alarmClock(Bell bell){//形参是 Bell 接口类型
System.out.println(bell.getClass());
bell.ring();//动态绑定
}
}
10.9.9 成员内部类的使用
代码:
package com.hspedu.innerclass;
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t 1();
//外部其他类,使用成员内部类的三种方式
//老韩解读
// 第一种方式
// outer08.new Inner08(); 相当于把 new Inner08()当做是 outer08 成员
// 这就是一个语法,不要特别的纠结.
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
// 第二方式 在外部类中,编写一个方法,可以返回 Inner08 对象
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
inner08Instance.say();
}
}
class Outer08 { //外部类
private int n1 = 10;
public String name = “张三”;
private void hi() {
System.out.println(“hi()方法…”);
}
//1.注意: 成员内部类,是定义在外部内的成员位置上
//2.可以添加任意访问修饰符(public 、protected 、默认、private), 因为它的地位就是一个成员
public class Inner08 {//成员内部类
private double sal = 99.8;
private int n1 = 66;
public void say() {
//可以直接访问外部类的所有成员,包含私有的
//如果成员内部类的成员和外部类的成员重名,会遵守就近原则.
// ,可以通过 外部类名.this.属性 来访问外部类的成员
System.out.println(“n1 = " + n1 + " name = " + name + " 外部类的 n1=” + Outer08.this.n1); hi();
}
}
//方法,返回一个 Inner08 实例
public Inner08 getInner08Instance(){
return new Inner08();
}
//写方法
public void t1() {
//使用成员内部类
//创建成员内部类的对象,然后使用相关的方法
Inner08 inner08 = new Inner08();
inner08.say();
System.out.println(inner08.sal);
}
}
10.9. 10 静态内部类的使用 StaticInnerClass01.java
代码:
package com.hspedu.innerclass;
public class StaticInnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类 使用静态内部类
//方式 1
//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//方式 2
//编写一个方法,可以返回静态内部类的对象实例.
Outer10.Inner10 inner101 = outer10.getInner10();
System.out.println(“============”);
inner101.say();
Outer10.Inner10 inner10_ = Outer10.getInner10_();
System.out.println(“************”);
inner10_.say();
}
}
class Outer10 { //外部类
private int n1 = 10;
private static String name = “张三”;
private static void cry() {}
//Inner10 就是静态内部类
//1. 放在外部类的成员位置
//2. 使用 static 修饰
//3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
//4. 可以添加任意访问修饰符(public 、protected 、默认、private), 因为它的地位就是一个成员 //5. 作用域 :同其他的成员,为整个类体
static class Inner10 {
private static String name = “韩顺平教育”;
public void say() {
//如果外部类和静态内部类的成员重名时,静态内部类访问的时,
//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)
System.out.println(name + " 外部类 name= " + Outer10.name);
cry();
}
}
public void m1() { //外部类—访问------>静态内部类 访问方式:创建对象,再访问
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10() {
return new Inner10();
}
public static Inner10 getInner10_() {
return new Inner10();
}
}
10.9. 11 课堂测试题
public class Test {//外部类
public Test() {//构造器
Inner s1 = new Inner();
s1.a = 10;
Inner s2 = new Inner();
System.out.println(s2.a);
}
class Inner { //内部类,成员内部类
public int a = 5;
}
public static void main(String[] args) {
Test t = new Test();
Inner r = t.new Inner();//5
System.out.println(r.a);//5
}
}
10. 10卖油翁和老黄牛
第 11 章枚举和注解
11. 1 先看一个需求
要求创建季节(Season) 对象,请设计并完成。Enumeration01.java
class Season{//类
private String name;
private String desc;//描述
//构造器
//getXX
//setXX
}
代码:
//package com.hspedu.enum_;
///**
// * @author 韩顺平
// * @version 1.0
// */
//public class Enumeration01 {
// public static void main(String[] args) {
// //使用
// Season spring = new Season(“春天”, “温暖”);
// Season winter = new Season(“冬天”, “寒冷”);
// Season summer = new Season(“夏天”, “炎热”);
// Season autumn = new Season(“秋天”, “凉爽”);
autumn.setName(“XXX”);
//
//
//
//
//
// } //} autumn.setDesc(“非常的热…”);
//因为对于季节而已,他的对象(具体值) ,是固定的四个,不会有更多
//安老师的这个设计类的思路,不能体现季节是固定的四个对象
//因此,这样的设计不好===> 枚举类[枚: 一个一个 举: 例举 , 即把具体的对象一个一个例举出来的类 // 就称为枚举类]
Season other = new Season(“红天”, “~~~”);
//class Season{//类
// private String name;
// private String desc;//描述
//
// public Season(String name, String desc) {
// this.name = name;
// this.desc = desc;
// }
//
// public String getName() {
// return name;
// }
//
// public void setName(String name) {
// this.name = name;
// }
//
// public String getDesc() {
//
//
//
//
//
//
//} return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
11.2 分析问题
11.2. 1 创建 Season 对象有如下特点
代码:
package com.hspedu.enum_;
/**
//演示字定义枚举实现
class Season {//类
private String name;
private String desc;//描述
//定义了四个对象, 固定.
public static final Season SPRING = new Season(“春天”, “温暖”);
public static final Season WINTER = new Season(“冬天”, “寒冷”);
public static final Season AUTUMN = new Season(“秋天”, “凉爽”);
public static final Season SUMMER = new Season(“夏天”, “炎热”);
//1. 将构造器私有化, 目的防止 直接 new
//2. 去掉 setXxx 方法, 防止属性被修改
//3. 在 Season 内部,直接创建固定的对象
//4. 优化,可以加入 final 修饰符
private Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return “Season{” +
“name='” + name + ‘’’ +
“, desc='” + desc + ‘’’ +
‘}’;
}
}
11.6 自定义类实现枚举-小结
11.6. 1 小结:进行自定义类实现枚举,有如下特点:
package com.hspedu.enum_;
/**
//定义了四个对象, 固定.
// public static final Season SPRING = new Season(“春天”, “温暖”);
// public static final Season WINTER = new Season(“冬天”, “寒冷”);
// public static final Season AUTUMN = new Season(“秋天”, “凉爽”);
// public static final Season SUMMER = new Season(“夏天”, “炎热”);
//如果使用了 enum 来实现枚举类
//1. 使用关键字 enum 替代 class
//2. public static final Season SPRING = new Season(“春天”, “温暖”) 直接使用
// SPRING(“春天”, “温暖”) 解读 常量名(实参列表)
//3. 如果有多个常量(对象) , 使用 ,号间隔即可
//4. 如果使用 enum 来实现枚举,要求将定义常量对象,写在前面
//5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()
SPRING(“春天”, “温暖”), WINTER(“冬天”, “寒冷”), AUTUMN(“秋天”, “凉爽”),
SUMMER(“夏天”, “炎热”)/, What()/;
private String name;
private String desc;//描述
private Season2() {//无参构造器
}
private Season2(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return “Season{” +
“name='” + name + ‘’’ +
“, desc='” + desc + ‘’’ +
‘}’;
}
}
11.7.2 enum 关键字实现枚举注意事项
当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum类, 而且是一个 final 类[如何证明],老师使用javap 工
具来演示
传统的 public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”) , 这里必
须知道,它调用的是哪个构造器.
如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
当有多个枚举对象时,使用, 间隔,最后有一个分号结尾
枚举对象必须放在枚举类的行首.
11.8 enum 关键字实现枚举-课堂练习
下面代码是否正确, 并说明表示的含义?
enum Gender{ //1min
BOY , GIRL; //这里其实就是调用 Gender 类的无参构造器
}
11.9 enum 常 2 用方法说明
说明:使用关键字 enum 时,会隐式继承 Enum类, 这样我们就可以使用 Enum 类相关的方法。[看下源码定义.]
public abstract class Enum
implements Comparable, Serializable {
}
我们一起来举例说明 enum 常用的方法的使用,对 Season2 测试. EnumMethod.java
package com.hspedu.enum_;
/**
//输出枚举对象的名字
System.out.println(autumn.name());
//ordinal() 输出的是该枚举对象的次序/编号,从 0 开始编号
//AUTUMN 枚举对象是第三个,因此输出 2
System.out.println(autumn.ordinal());
//从反编译可以看出 values 方法,返回 Season2[]
//含有定义的所有枚举对象
Season2[] values = Season2.values();
System.out.println(“=遍历取出枚举对象(增强 for)==”);
for (Season2 season: values) {//增强 for 循环
System.out.println(season);
}
//valueOf:将字符串转换成枚举对象,要求字符串必须
为已有的常量名,否则报异常
//执行流程
//1. 根据你输入的 “AUTUMN” 到 Season2 的枚举对象去查找
//2. 如果找到了,就返回,如果没有找到,就报错
Season2 autumn1 = Season2.valueOf(“AUTUMN”);
System.out.println(“autumn1=” + autumn1);
System.out.println(autumn == autumn1);
//compareTo:比较两个枚举常量,比较的就是编号
//老韩解读
//1. 就是把 Season2.AUTUMN 枚举对象的编号 和 Season2.SUMMER 枚举对象的编号比较 //2. 看看结果
/*
public final int compareTo(E o) {
return self.ordinal - other.ordinal;
}
Season2.AUTUMN 的编号[2] - Season2.SUMMER 的编号[3]
*/
System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));
//
//
//
//
//
//
//
//
//
//
//
}
} //补充了一个增强 for
int[] nums = { 1, 2, 9};
//普通的 for 循环
System.out.println(“=普通的 for=”);
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
System.out.println(“=增强的 for=”);
//执行流程是 依次从 nums 数组中取出数据,赋给i, 如果取出完毕,则退出for
for(int i : nums) {
System.out.println(“i=” + i);
}
课堂完成 EnumExercise02.java
声明 Week 枚举类,其中包含星期一至星期 日的定义; MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,
SATURDAY, SUNDAY;
使用 values 返回所有的枚举数组, 并遍历 , 输出左图效果
5min 完成
package com.hspedu.enum_;
/**
/*
声明 Week 枚举类,其中包含星期一至星期日的定义;
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
使用 values 返回所有的枚举数组, 并遍历 , 输出左图效果
*/
enum Week {
//定义 Week 的枚举对象
MONDAY(“星期一”), TUESDAY(“星期二”), WEDNESDAY(“星期三”), THURSDAY(“星期四”), FRIDAY(“星期五”), SATURDAY(“星期六”), SUNDAY(“星期日”);
private String name;
private Week(String name) {//构造器
this.name = name;
}
@Override
public String toString() {
return name;
}
}
11. 11enum 实现接口
EnumDetail.java
package com.hspedu.enum_;
/**
//1.使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum ,而 Java 是单继承机制 //enum Season3 extends A {
//
//}
//2.enum 实现的枚举类,仍然是一个类,所以还是可以实现接口的.
interface IPlaying {
public void playing();
}
enum Music implements IPlaying {
CLASSICMUSIC;
@Override
public void playing() {
System.out.println(“播放好听的音乐…”);
}
}
11. 12注解的理解
注解(Annotation)也被称为元数据(Metadata) ,用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。
和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角 色,例如用来配置应用程序的任何切面,代替java EE 旧版中所遗留的繁冗代码和 XML 配置等。
package com.hspedu.annotation_;
/**
}
}
class Father{//父类
public void fly(){
System.out.println(“Father fly…”);
}
public void say(){}
}
class Son extends Father {//子类
//老韩解读
//1. @Override 注解放在 fly 方法上,表示子类的 fly 方法时重写了父类的 fly
//2. 这里如果没有写 @Override 还是重写了父类 fly
//3. 如果你写了@Override 注解,编译器就会去检查该方法是否真的重写了父类的
// 方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
//4. 看看 @Override 的定义
// 解读: 如果发现 @interface 表示一个 注解类
/*
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
*/
@Override //说明
public void fly() {
System.out.println(“Son fly…”);
}
@Override
public void say() {}
}
package com.hspedu.annotation_;
/**
//老韩解读
//1. @Deprecated 修饰某个元素, 表示该元素已经过时
//2. 即不在推荐使用,但是仍然可以使用
//3. 查看 @Deprecated 注解类的源码
//4. 可以修饰方法,类,字段, 包, 参数 等等
//5. @Deprecated 可以做版本升级过渡使用
/*
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated {
}
*/
@Deprecated
class A {
@Deprecated
public int n1 = 10;
@Deprecated
public void hi(){
}
}
package com.hspedu.annotation_;
import java.util.ArrayList;
import java.util.List;
/**
//老韩解读
//1. 当我们不希望看到这些警告的时候,可以使用 SuppressWarnings 注解来抑制警告信息
//2. 在{“”} 中,可以写入你希望抑制(不显示)警告信息
//3. 可以指定的警告类型有
//
//
//
//
//
//
//
//
//
// all ,抑制所有警告
boxing ,抑制与封装/拆装作业相关的警告
//cast ,抑制与强制转型作业相关的警告
//dep-ann ,抑制与淘汰注释相关的警告
//deprecation ,抑制与淘汰的相关警告
//fallthrough ,抑制与 switch 陈述式中遗漏 break 相关的警告
//finally ,抑制与未传回 finally 区块相关的警告
//hiding ,抑制与隐藏变数的区域变数相关的警告
//incomplete-switch ,抑制与 switch 陈述式(enum case)中遗漏项目相关的警告
//javadoc ,抑制与javadoc 相关的警告
//
//
//
//
//
//
//
//
//
//
//
//
//
// //nls ,抑制与非 nls 字串文字相关的警告
//null ,抑制与空值分析相关的警告
//rawtypes ,抑制与使用 raw 类型相关的警告
//resource ,抑制与使用 Closeable 类型的资源相关的警告
//restriction ,抑制与使用不建议或禁止参照相关的警告
//serial ,抑制与可序列化的类别遗漏 serialVersionUID 栏位相关的警告
//static-access ,抑制与静态存取不正确相关的警告
//static-method ,抑制与可能宣告为 static 的方法相关的警告
//super ,抑制与置换方法相关但不含 super 呼叫的警告
//synthetic-access ,抑制与内部类别的存取未最佳化相关的警告
//sync-override ,抑制因为置换同步方法而遗漏同步化的警告
//unchecked ,抑制与未检查的作业相关的警告
//unqualified-field-access ,抑制与栏位存取不合格相关的警告
//unused ,抑制与未用的程式码及停用的程式码相关的警告
//4. 关于 SuppressWarnings 作用范围是和你放置的位置相关
// 比如 @SuppressWarnings 放置在 main 方法,那么抑制警告的范围就是 main
// 通常我们可以放置具体的语句, 方法, 类.
//5. 看看 @SuppressWarnings 源码
//(1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE //(2) 该注解类有数组 String[] values() 设置一个数组比如 {“rawtypes”, “unchecked”, “unused”}
/*
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
*/
public static void main(String[] args) {
List list = new ArrayList();
list.add(“jack”);
list.add(“tom”);
list.add(“mary”);
int i;
System.out.println(list.get(1));
}
public void f1() {
// @SuppressWarnings({“rawtypes”})
List list = new ArrayList();
//
}
}
list.add(“jack”);
list.add(“tom”);
list.add(“mary”);
@SuppressWarnings({“unused”})
int i;
System.out.println(list.get(1));
说明
只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy
类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值:
@Retention 的三种值
RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释
RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。 这是默认 值
RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以
通过反射获取该注解
15.4 @Target
15.5 @Documented
15.6 @Inherited 注解
16第 10 章作业
第 12 章异常-Exception
12. 1 看个实际的问题和一段代码
运行下面的代码,看看有什么问题-> 引出异常和异常处理机制 Exception01.java
public static void main(String[] args) {
int num1 = 10;
int num2 = 0;
int res = num1 / num2;
System.out.println(“程序继续运行…”);
}
12.2 解决方案-异常捕获
对异常进行捕获,保证程序可以继续运行.
看老师的代码演示 try-catch
package com.hspedu.exception_;
/**
//1. num1 / num2 => 10 / 0
//2. 当执行到 num1 / num2 因为 num2 = 0, 程序就会出现(抛出)异常 ArithmeticException
//3. 当抛出异常后,程序就退出,崩溃了 , 下面的代码就不在执行
//4. 大家想想这样的程序好吗? 不好,不应该出现了一个不算致命的问题,就导致整个系统崩溃 //5. java 设计者,提供了一个叫 异常处理机制来解决该问题
int res = num1 / num2;
//如果程序员,认为一段代码可能出现异常/问题,可以使用 try-catch 异常处理机制来解决 //从而保证程序的健壮性
//将该代码块->选中->快捷键 ctrl + alt + t -> 选中 try-catch
//6. 如果进行异常处理,那么即使出现了异常,程序可以继续执行
try {
int res = num1 / num2;
} catch (Exception e) {
//e.printStackTrace();
System.out.println(“出现异常的原因=” + e.getMessage());//输出异常信息
}
System.out.println(“程序继续运行…”);
}
}
12.3 异常介绍
12.4 异常体系图一览
12.4. 1 异常体系图
12.4.2 异常体系图的小结
12.5 常见的运行时异常
12.5. 1 常见的运行时异常包括
代码:
package com.hspedu.exception_;
/**
@author 韩顺平
@version 1.0
*/
public class NullPointerException_ {
public static void main(String[] args) {
String name = null;
System.out.println(name.length());
}
}
代码:
package com.hspedu.exception_;
/**
int num = Integer.parseInt(name);//抛出 NumberFormatException
System.out.println(num);//1234
}
}
代码
package com.hspedu.exception_;
/**
}
}
代码:
package com.hspedu.exception_;
/**
代码:
package com.hspedu.exception_;
/**
12.6. 1 介绍
12.6.2 常见的编译异常
12.6.3 案例说明
代码
package com.hspedu.exception_;
import java.io.FileInputStream;
import java.io.IOException;
/**
FileInputStream fis;
fis = new FileInputStream(“d:\aa.jpg”);
int len;
while ((len = fis.read()) != - 1) {
System.out.println(len);
}
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
12.7 异常课堂练习
看看下面代码是否正确,为什么? 课堂练习4 个题 4min
12.8 异常处理
12.8. 1 基本介绍
12.8.2 异常处理的方式
12.8.3 示意图
12.9 try-catch 异常处理
12.9. 1 try-catch 方式处理异常说明 TryCatch01.java
12.9.2 try-catch 方式处理异常-快速入门
代码:
public static void main(String[] args) {
int num1 = 10;
int num2 = 0;
try {
int res = num1 / num2;
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
12.9.3 try-catch 方式处理异常-注意事项 TryCatchDetail.java
代码
package com.hspedu.try_;
/**
public class TryCatchDetail {
public static void main(String[] args) {
//ctrl + atl + t
//老韩解读
//1. 如果异常发生了,则异常发生后面的代码不会执行,直接进入到 catch 块
//2. 如果异常没有发生,则顺序执行 try 的代码块,不会进入到 catch
//3. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用如下代码- finally try {
String str = “韩顺平”;
int a = Integer.parseInt(str);
System.out.println(“数字:” + a);
} catch (NumberFormatException e) {
System.out.println(“异常信息=” + e.getMessage());
} finally {
System.out.println(“finally 代码块被执行…”);
}
System.out.println(“程序继续…”);
}
}
代码
package com.hspedu.try_;
/**
//老韩解读
//1.如果 try 代码块有可能有多个异常
//2.可以使用多个 catch 分别捕获不同的异常,相应处理
//3.要求子类异常写在前面,父类异常写在后面
try {
Person person = new Person();
//person = null;
System.out.println(person.getName());//NullPointerException
int n1 = 10;
int n2 = 0;
int res = n1 / n2;//ArithmeticException
} catch (NullPointerException e) {
System.out.println(“空指针异常=” + e.getMessage());
} catch (ArithmeticException e) {
System.out.println(“算术异常=” + e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
}
}
}
class Person {
private String name = “jack”;
public String getName() {
return name;
}
}
代码:
package com.hspedu.try_;
/**
/*
可以进行 try-finally 配合使用, 这种用法相当于没有捕获异常,
因此程序会直接崩掉/退出。应用场景,就是执行一段代码,不管是否发生异常,
都必须执行某个业务逻辑
*/
try{
int n1 = 10;
int n2 = 0;
System.out.println(n1 / n2);
}finally {
System.out.println(“执行了 finally…”);
}
System.out.println(“程序继续执行…”);
}
}
12.9.4 异常处理课堂练习
题 1 TryCatchExercise01.java
题 2TryCatchExercise02.java
题 3TryCatchExercise03.java
12.9.5 try-catch-finally 执行顺序小结
12.9.6 课后练习题: TryCatchExercise04.java
如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
package com.hspedu.try_;
import java.util.Scanner;
/**
//如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
//思路
//1. 创建 Scanner 对象
//2. 使用无限循环,去接收一个输入
//3. 然后将该输入的值,转成一个 int
//4. 如果在转换时,抛出异常,说明输入的内容不是一个可以转成int 的内容
//5. 如果没有抛出异常,则 break 该循环
Scanner scanner = new Scanner(System.in);
int num = 0;
String inputStr = “”;
while (true) {
System.out.println(“请输入一个整数:”); //
inputStr = scanner.next();
try {
num = Integer.parseInt(inputStr); //这里是可能抛出异常
break;
} catch (NumberFormatException e) {
System.out.println(“你输入的不是一个整数:”);
}
}
System.out.println(“你输入的值是=” + num);
}
}
10throws 异常处理
10.2 快速入门案例
10.3 注意事项和使用细节 ThrowsDetail.java
代码:
package com.hspedu.throws_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/**
public static void f2() /throws ArithmeticException/ {
//1.对于编译异常,程序中必须处理,比如 try-catch 或者 throws
//2.对于运行时异常,程序中如果没有处理,默认就是throws 的方式处理
int n1 = 10;
int n2 = 0;
double res = n1 / n2;
}
public static void f1() throws FileNotFoundException {
//这里大家思考问题 调用f3() 报错
//老韩解读
//1. 因为 f3() 方法抛出的是一个编译异常
//2. 即这时,就要 f1() 必须处理这个编译异常
//3. 在 f1() 中,要么 try-catch-finally ,或者继续 throws 这个编译异常
f3(); // 抛出异常
}
public static void f3() throws FileNotFoundException {
FileInputStream fis = new FileInputStream(“d://aa.txt”);
}
public static void f4() {
//老韩解读:
//1. 在 f4()中调用方法 f5() 是 OK
//2. 原因是 f5() 抛出的是运行异常
//3. 而java 中,并不要求程序员显示处理, 因为有默认处理机制
f5();
}
public static void f5() throws ArithmeticException {
}
}
class Father { //父类
public void method() throws RuntimeException {
}
}
class Son extends Father {//子类
//3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,
// 所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型
//4. 在 throws 过程中,如果有方法 try-catch , 就相当于处理异常,就可以不必 throws
@Override
public void method() throws ArithmeticException {
}
}
12. 11自定义异常
12. 11. 1 基本概念
11.2 自定义异常的步骤
11.3 自定义异常的应用实例 CustomException.java
代码:
package com.hspedu.customexception_;
/**
int age = 180;
//要求范围在 18 – 120 之间,否则抛出一个自定义异常
if(!(age >= 18 && age <= 120)) {
//这里我们可以通过构造器,设置信息
throw new AgeException(“年龄需要在 18~ 120 之间”);
}
System.out.println(“你的年龄范围正确.”);
}
}
//自定义一个异常
//老韩解读
//1. 一般情况下,我们自定义异常是继承 RuntimeException
//2. 即把自定义异常做成 运行时异常,好处时,我们可以使用默认的处理机制
//3. 即比较方便
class AgeException extends RuntimeException {
public AgeException(String message) {//构造器
super(message);
}
}
12. 12throw 和 throws 的区别
12. 12. 1 一览表
12.2 测试题-下面的测试输出什么 ThrowException.java 2min
13本章作业
第 13 章常用类
13. 1 包装类
13. 1. 1 包装类的分类 WrapperType.java
1.2 包装类和基本数据的转换
1.3 案例演示 Integer01.java
package com.hspedu.wrapper;
/**
//手动拆箱
//Integer -> int
int i = integer.intValue();
//jdk5 后,就可以自动装箱和自动拆箱
int n2 = 200;
//自动装箱 int->Integer
Integer integer2 = n2; //底层使用的是 Integer.valueOf(n2)
//自动拆箱 Integer->int
int n3 = integer2; //底层仍然使用的是 intValue()方法
}
}
13. 1.4 课堂测试题 WrapperExercise01.java 2min
package com.hspedu.wrapper;
/**
//方式 1
String str1 = i + “”;
//方式 2
String str2 = i.toString();
//方式 3
String str3 = String.valueOf(i);
//String -> 包装类(Integer)
String str4 = “12345”;
Integer i2 = Integer.parseInt(str4);//使用到自动装箱
Integer i3 = new Integer(str4);//构造器
System.out.println(“ok~~”);
}
}
13. 1.6 Integer 类和 Character 类的常用方法
package com.hspedu.wrapper;
/**
public class WrapperMethod {
public static void main(String[] args) {
System.out.println(Integer.MIN_VALUE); //返回最小值
System.out.println(Integer.MAX_VALUE);//返回最大值
System.out.println(Character.isDigit(‘a’));//判断是不是数字
System.out.println(Character.isLetter(‘a’));//判断是不是字母
System.out.println(Character.isUpperCase(‘a’));//判断是不是大写
System.out.println(Character.isLowerCase(‘a’));//判断是不是小写
System.out.println(Character.isWhitespace(‘a’));//判断是不是空格
System.out.println(Character.toUpperCase(‘a’));//转成大写
System.out.println(Character.toLowerCase(‘A’));//转成小写
}
}
13. 1.7 Integer 类面试题 1 WrapperExercise02.java
看看下面代码,输出什么结果? 为什么? 2min
package com.hspedu.wrapper;
/**
public static void main(String[] args) {
Integer i = new Integer( 1);
Integer j = new Integer( 1);
System.out.println(i == j); //False
//所以,这里主要是看范围 - 128 ~ 127 就是直接返回
/*
老韩解读
//1. 如果 i 在 IntegerCache.low(- 128)~IntegerCache.high(127),就直接从数组返回
//2. 如果不在 - 128~ 127,就直接 new Integer(i)
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
*/
Integer m = 1; //底层 Integer.valueOf(1); -> 阅读源码
Integer n = 1;//底层 Integer.valueOf(1);
System.out.println(m == n); //T
//所以,这里主要是看范围 - 128 ~ 127 就是直接返回
// ,否则,就 new Integer(xx);
Integer x = 128;//底层 Integer.valueOf(1);
Integer y = 128;//底层 Integer.valueOf(1);
System.out.println(x == y);//False
}
}
package com.hspedu.wrapper;
/**
//示例三
Integer i5 = 127;//底层 Integer.valueOf(127)
Integer i6 = 127;//- 128~ 127
System.out.println(i5 == i6); //T
//示例四
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8);//F
//示例五
Integer i9 = 127; //Integer.valueOf(127)
Integer i 10 = new Integer( 127);
System.out.println(i9 == i10);//F
//示例六
Integer i 11= 127;
int i12= 127;
//只有有基本数据类型,判断的是
//值是否相同
System.out.println(i11i12); //T
//示例七
Integer i 13= 128;
int i14= 128;
System.out.println(i13i14);//T
}
}
13.2 String 类
13.2. 1 String 类的理解和创建对象
代码:
package com.hspedu.string_;
/**
// 常用的有 String s1 = new String(); //
//String s2 = new String(String original);
//String s3 = new String(char[] a);
//String s4 = new String(char[] a,int startIndex,int count)
//String s5 = new String(byte[] b)
//5. String 类实现了接口 Serializable【String 可以串行化:可以在网络传输】
// 接口 Comparable [String 对象可以比较大小]
//6. String 是 final 类,不能被其他的类继承
//7. String 有属性 private final char value[]; 用于存放字符串内容
//8. 一定要注意:value 是一个 final 类型, 不可以修改(需要功力):即 value 不能指向
// 新的地址,但是单个字符内容是可以变化
String name = “jack”;
name = “tom”;
final char[] value = {‘a’,‘b’,‘c’};
char[] v2 = {‘t’,‘o’,‘m’};
value[0] = ‘H’;
//value = v2; 不可以修改 value 地址
}
}
13.2.2 创建 String 对象的两种方式
13.2.3 两种创建 String 对象的区别
13.2.4 课堂测试题 StringExercise01.java
对应的示意图:
13.3 字符串的特性
13.3. 1 说明 StringExercise06.java
13.3.2 面试题
13.4 String 类的常见方法
13.4. 1 说明
13.4.2 String 类的常见方法一览
代码:
package com.hspedu.string_;
/**
String str2 = “Hello”;
System.out.println(str1.equals(str2));//
// 2.equalsIgnoreCase 忽略大小写的判断内容是否相等
String username = “johN”;
if (“john”.equalsIgnoreCase(username)) {
System.out.println(“Success!”);
} else {
System.out.println(“Failure!”);
}
// 3.length 获取字符的个数,字符串的长度
System.out.println(“韩顺平”.length());
// 4.indexOf 获取字符在字符串对象中第一次出现的索引,索引从 0 开始,如果找不到,返回- 1 String s1 = “wer@terwe@g”;
int index = s1.indexOf(‘@’);
System.out.println(index);// 3
System.out.println(“weIndex=” + s1.indexOf(“we”));//0
// 5.lastIndexOf 获取字符在字符串中最后一次出现的索引,索引从 0 开始,如果找不到,返回- 1 s1 = “wer@terwe@g@”;
index = s1.lastIndexOf(‘@’);
System.out.println(index);//11
System.out.println(“ter 的位置=” + s1.lastIndexOf(“ter”));//4
// 6.substring 截取指定范围的子串
String name = “hello,张三”;
//下面 name.substring(6) 从索引 6 开始截取后面所有的内容
System.out.println(name.substring(6));//截取后面的字符
//name.substring(0,5)表示从索引 0 开始截取,截取到索引 5- 1=4 位置
System.out.println(name.substring(2,5));//llo
}
}
package com.hspedu.string_;
/**
System.out.println(s.toLowerCase());//hello
// 3.concat 拼接字符串
String s1 = “宝玉”;
s1 = s1.concat(“林黛玉”).concat(“薛宝钗”).concat(“together”);
System.out.println(s1);//宝玉林黛玉薛宝钗 together
// 4.replace 替换字符串中的字符
s1 = “宝玉 and 林黛玉 林黛玉 林黛玉”;
//在 s1 中,将 所有的 林黛玉 替换成薛宝钗
// 老韩解读: s1.replace() 方法执行后,返回的结果才是替换过的.
// 注意对 s1 没有任何影响
String s11 = s1.replace(“宝玉”, “jack”);
System.out.println(s1);//宝玉 and 林黛玉 林黛玉 林黛玉
System.out.println(s11);//jack and 林黛玉 林黛玉 林黛玉
// 5.split 分割字符串, 对于某些分割字符,我们需要 转义比如 | \等
String poem = “锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦”;
//老韩解读:
// 1. 以 , 为标准对 poem 进行分割 , 返回一个数组
// 2. 在对字符串进行分割时,如果有特殊字符,需要加入 转义符
String[] split = poem.split(“,”);
poem = “E:\aaa\bbb”;
split = poem.split(“\\”);
System.out.println(“分割后内容=”);
for (int i = 0; i < split.length; i++) {
System.out.println(split[i]);
}
// 6.toCharArray 转换成字符数组
s = “happy”;
char[] chs = s.toCharArray();
for (int i = 0; i < chs.length; i++) {
System.out.println(chs[i]);
}
// 7.com