目录
一 Java概述
Java特性
跨平台
跨平台的根本原因:jvm
环境变量配置
理解:2.告诉计算机我的jdk安装目录
3.告诉计算机到java_home下的bin目录去找运行的指令
命令行编译乱码及解决
设置文件的编码与控制台一样再保存
运行的是study这个类,而不是study.class这个文件,所以不带.class
Java运行过程
注意事项
6.编译后每一个类都对应的生成一个.class文件
第八点
Java学习方法
第六条永无止境
Java转义符
控制台用Tab键:自动补齐
重点区分换行和回车
换行 \n: 光标调到下一行
回车 \r:光标回到句首
初学易犯错误
注释
多行注释不能嵌套
文档注释(用得挺多的)
可以用命令生成说明文档
代码规范
Dos指令(了解)
相对路径绝对路径
二、变量
变量基本原理、概念
变量是程序的基本组成单位
变量两种初始化:1)先声明,在赋值。2)声明的同时直接赋值(初始化)
程序中 + 号的使用
数据类型(背)
这几个背下来
Int类型使用细节
浮点型与浮点型使用细节
浮点型的陷阱!!
//浮点型数据做运算后不能直接比较,因为内存里存的都是近似值,
//做运算后得到的也是近似值
可以按需要规定一个相差范围。满足即认为两个数相等
如果是直接查询或者直接赋值得到的小数,是可以直接判断相等的
JAVA API文档
字符类型char、char细节
字符类型可以表示单个字符,字符类型是 char,char 是两个字节(可以存放汉字),多个字符我们用字符串String
字符细节
字符本质探讨、字符编码
常见字符编码介绍
布尔类型boolean
在java中
Java自动转换+细节(背)
背!
自动转换细节.
细节4:byte、short、char他们三者不管是相互运算还是混合运算结果都是 int
强制类型转换、细节
谨慎!谨慎使用
强制类型转换细节
基本数据类型与String的转换
charAt()是字符串类型的一个方法,是返回字符串指定索引位置的字符。(只能从字符串中截取)
基本数据类型与String转换细节
三 运算符
算术运算符
介绍
取模运算
本质
除法 /
关系运算符
逻辑运算符
分析方法
1) 短路与 && , 短路或 ||,取反 !
2) 逻辑与 &,逻辑或 |,^
ü 说明逻辑运算规则:
1) a&b : & 叫逻辑与:规则:当 a 和 b 同时为 true ,则结果为 true, 否则为 false
2) a&&b : && 叫短路与:规则:当 a 和 b 同时为 true ,则结果为 true,否则为 false
3) a|b : | 叫逻辑或,规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false
4) a||b : || 叫短路或,规则:当 a 和 b ,有一个为 true ,则结果为 true,否则为 false
5) !a : 叫取反,或者非运算。当 a 为 true, 则结果为 false, 当 a 为 false 是,结果为 true
6) a^b: 叫逻辑异或,当 a 和 b 不同时,则结果为 true, 否则为 false
//看看区别 :
(1)||短路或:如果第一个条件为 true, 则第二个条件不会判断,最终结果为 true,效率高
(2)| 逻辑或:不管第一个条件是否为 true,第二个条件都要判断,效率低
赋值运算符
复合赋值运算会进行强制类型转换 ,如
复合赋值运算细节
1) 运算顺序从右往左 int num = a + b + c;
2) 赋值运算符的左边 只能是变量,右边 可以是变量、表达式、常量值 int num = 20; int num2= 78 * 34 - 10; int num3 = a;
3) 复合赋值运算符等价于下面的效果 比如:a+=3;等价于 a=a+3; 其他类推
4) 复合赋值运算符会进行类型转换。 byte b
三元运算符
4.6.1基本语法
条件表达式 ? 表达式 1: 表达式 2;
运算规则:
1. 如果条件表达式为 true,运算后的结果是表达式 1;
2. 如果条件表达式为 false,运算后的结果是表达式 2;
口诀: [一灯大师:一真大师]
细节
运算符优先级(多用,别刻意背)
标识符的命名规则和规范
命名规范
1) 包名:多单词组成时所有字母都小写:aaa.bbb.ccc //比如 com.hsp.crm
2) 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz [大驼峰]
比如: TankShotGame
3) 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz [小驼峰, 简称 驼峰法]
比如: tankShotGame
4) 常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ
比如 :定义一个所得税率 TAX_RATE
5) 后面我们学习到 类,包,接口,等时,我们的命名规范要这样遵守,更加详细的看文档.
键盘输入
System.in代表从键盘输入
4.11.1 介绍
在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。Input.java , 需要一个 扫描器(对象), 就是
Scanner
4.11.2 步骤 :
1) 导入该类的所在包, java.util.*
2) 创建该类对象(声明变量)
3) 调用里面的功能
进制(程序员基本功)
介绍
对于整数,有四种表示方式:
二进制: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 不区分大小写.
图示
进制转换
第一组:
- 二进制转十进制
- 八进制转十进制
- 十六进制转十进制
规则:从最低位(右边)开始,将每个位上的数提取出来,乘以 16 的(位数-1)次方,然后求和。
案例:请将 0x23A 转成十进制的数
0x23A = 10 * 16^0 + 3 * 16 ^ 1 + 2 * 16^2 =
第二组:
- 十进制转二进制
规则:将该数不断除以 2,直到商为 0 为止,然后将每步得到的余数倒过来,就是对应的二进制。
案例:请将 34 转成二进制 = 0B0010001
- 十进制转八进制
规则:将该数不断除以 8,直到商为 0 为止,然后将每步得到的余数倒过来,就是对应的八进制。 案例:请将 131 转成八进制 => 0203
- 十进制转十六进制
规则:将该数不断除以 16,直到商为 0 为止,然后将每步得到的余数倒过来,就是对应的十六进制。 案例:请将 237 转成十六进制 => 0xED
第三组
- 二进制转八进制
规则:从低位开始,将二进制数每三位一组,转成对应的八进制数即可
- 二进制转十六进制
从低位开始,将二进制数每四位一组,转成对应的十六进制数即可。
第四组
- 八进制转二进制
从低位开始,将二进制数每四位一组,转成对应的十六进制数即可。
- 十六进制转二进制
规则:将十六进制数每 1 位,转成对应的 4 位的一个二进制数即可
二进制在运算中的说明
原码 反码 补码(重点. 难点) 背下来
位运算符
还有 3 个位运算符 >>、<< 和 >>> , 运算规则:
1) 算术右移 >>:低位溢出,符号位不变,并用符号位补溢出的高位
2) 算术左移 <<: 符号位不变,低位补 0
3) >>> 逻辑右移也叫无符号右移,运算规则是: 低位溢出,高位补 0
4) 特别说明:没有 <<< 符号
Chaper04: BitOperator.java BitOperator01.java
Tip:
- 溢出就是扔掉的意思
- >>算术右移本质: 移动一位就相当于除以一个2( <<同理 )
第四章 程序控制结构
分支结构
If-else结构
单分支
双分支
多分支
细节:多分支结构找到一个执行入口后,后面的分支就不再判断了
多分支的流程图
嵌套分支
在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分支外面的分支结构称为外层分支。老师建议: 不要超过 3 层 (可读性不好)
Switch分支结构
Default后面有没有break都会退出switch.
基本语法
Switch流程图(理解)
Switch注意事项与细节
If-else与switch的选择
循环结构
for循环
基本语法
流程图
For细节和注意事项
内存分析
死循环
编程思想(理解 练习)
//老韩的两个编程思想(技巧)
1. 化繁为简 : 即将复杂的需求,拆解成简单的需求,逐步完成 编程 = 思想 --练习-> 代码
2. 先死后活 : 先考虑固定的值,然后转成可以灵活变化的值
While循环
基本语法
流程图
内存分析图
While注意事项和细节
1) 循环条件是返回一个布尔值的表达式
2) while 循环是先判断再执行语句
Do while循环
基本语法
老韩说明:
1. do while 是关键字
1. 也有循环四要素, 只是位置不一样
2. 先执行,再判断,也就是说,一定会至少执行一次
3. 最后 有一个 分号 ;
4. while 和 do..while 区别举例:
流程图
Do while注意事项
1) 循环条件是返回一个布尔值的表达式
2) do..while 循环是先执行,再判断, 因此它至少执行一
多重循环控制(重点!难点!)
1) 将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for ,while ,do…while 均可以作为外层循环和内层循环。
【建议一般使用两层,最多不要超过 3 层, 否则,代码的可读性很差】
2) 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为 false 时,才会完全跳出内
层循环,才可结束外层的当次循环,开始下一次的循环[听不懂,走案例]。
- 设外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n次
请分析 下面的多重循环执行步骤, 并写出输出 => 韩老师的内存分析法
//双层 for MulFor.java
for(int i = 0; i < 2; i++) { //先思考
for( int j = 0; j < 3; j++) {
System.out.println("i=" + i + j=" + j);
}
}
Break语句
跳转控制语句 – continue
基本介绍:
1) continue 语句用于结束本次循环,继续执行下一次循环。
2) continue 语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这个和前面的标签的
使用的规则一样
流程图
跳转控制语句-return
Return使用在方法中, 表示退出所在方法, 若使用在main方法中,则代表退出程序
六 数组
简介
数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型。 即:数(数据)组(一组)就是一组数据
定义
Int[ ] array = {…} 等价于 int array[ ] = {…}
数组的使用
使用方式1 : 动态初始化
使用方式 2-动态初始化
先声明数组
语法:数据类型 数组名[]; 也可以 数据类型[] 数组名;
int a[]; 或者 int[] a;
创建数组
语法: 数组名=new 数据类型[大小];
a=new int[10]
示例:
第 2 种动态分配方式, 先声明数组,再 new 分配空间
double scores[] ; //声明数组, 这时 scores 是 null
scores = new double[5]; // 分配内存空间,可以存放数据
使用方式3:静态初始化
数组细节、默认值
数组使用注意事项和细节
1) 数组是多个相同类型数据的组合,实现对这些数据的统一管理
2) 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用。
3) 数组创建后,如果没有赋值,有默认值
int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
- 使用数组的步骤 1. 声明数组并开辟空间 2 给数组各个元素赋值 3 使用数组
注: // 任何一个办法声明后java内存里面分配好了地址了已经,所以不能同时使用静态和动态初始化。java只分配一次内存
如 : int[] a = new int[6]; a = {1,2,3,4,5,6}; 错!
5) 数组的下标是从 0 开始的。
6) 数组下标必须在指定范围内使用,否则报:下标越界异常,比如
int [] arr=new int[5]; 则有效下标为 0-4
7) 数组属引用类型,数组型数据是对象(object)
数组赋值机制 (理解 背)
1) 基本数据类型赋值,这个值就是具体的数据,而且相互不影响。
int n1 = 2; int n2 = n1;
2) 数组在默认情况下是引用传递,赋的值是地址。
看一个案例,并分析数组赋值的内存图(重点, 难点. )。
//代码 ArrayAssign.java
int[] arr1 = {1,2,3};
int[] arr2 = arr1;
在内存中,只要分配了一个数据空间,就一定会对应一个地址
基本数据类型: 值传递,各自有存储空间
引用数据类型: 址传递(引用传递),指向同一块存储地址
数组拷贝
将 int[] arr1 = {10,20,30}; 拷贝到 arr2 数组, 要求数据空间是独立的.
每个数组都有独立的空间
数组反转 添加/扩容
数组添加/扩容
要求:实现动态的给数组添加元素效果,实现对数组扩容。ArrayAdd.java
1) 原始数组使用静态分配 int[] arr = {1,2,3}
2) 增加的元素 4,直接放在数组的最后 arr = {1,2,3,4}
3) 用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n
//总结
// 1.数组是引用类型,他指向一个内存空间
// 1.1所以无论两个数组之间长度相差多少,都可以直接赋值 , 因为他仅仅是改变一个地址,原来的空间会被回收
二维数组
二维数组赋值机制(重要)
二维数组不直接指向数据
它先指向一个空间,这个空间存放的是一维数组的地址,然后再指向一个真正存放数据的空间
初始化方式
:动态初始化1
TwoDimensionalArray02.java
1) 语法: 类型[][] 数组名=new 类型[大小][大小]
2) 比如: int a[][]=new int[2][3]
动态初始化2
先声明:类型 数组名[][]; TwoDimensionalArray02.java
再定义(开辟空间) 数组名 = new 类型[大小][大小]
赋值(有默认值,比如 int 类型的就是 0
动态初始化3:列数不确定 TwoDimensionalArray03
原理图
使用方式 4: 静态初始化
TwoDimensionalArray04.java
定义 类型 数组名[][] = {{值 1,值 2..},{值 1,值 2..},{值 1,值 2..}}
使用即可 [ 固定方式访问 ]
比如:
int[][] arr = {{1,1,1}, {8,8,9}, {100}};
解读
- 定义了一个二维数组 arr
2. arr 有三个元素(每个元素都是一维数组)
3. 第一个一维数组有 3 个元素 , 第二个一维数组有 3 个元素, 第三个一维数组有 1 个元素
注: 第三个一维数组的括号不能省略 ,否则类型不匹配, 如:
int[][] arr = {{1,1,1}, {8,8,9}, 100};
七、面向对象编程(基础部分)
简介 引出
7.1 类与对象
7.1.1看一个养猫猫问题
张老太养了两只猫猫:一只名字叫小白,今年 3 岁,白色。还有一只叫小花,今年 100 岁,花色。请编写一个程序,当用户
输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示 张老太没有这只猫猫。
7.1.2使用现有技术解决 Object01.java
1) 单独的定义变量解决
2) 使用数组解决
7.1.3现有技术解决的缺点分析
不利于数据的管理
效率低===》 引出我们的新知识点 类与对象 哲学, 道家思想
java 设计者 引入 类与对象(OOP) ,根本原因就是现有的技术,不能完美的解决新的新的需求
类与对象关系示意图
类和对象的区别和联系
1) 类是抽象的,概念的,代表一类事物,比如人类,猫类.., 即它是数据类型.
2) 对象是具体的,实际的,代表一个具体事物, 即 是实例.
3) 类是对象的模板,对象是类的一个个体,对应一个实例
对象在内存中存在形式(重要的)必须搞清楚
解读:
1.基本数据类型直接放在堆中
2.引用数据类型在堆中存放的是地址,实际内容存放在方法区中的常量池中
3.创建对象的时候会把类的信息加载到方法区
属性/成员变量/字段 细节、注意事项
介绍
- 从概念或叫法上看: 成员变量 = 属性 = field(字段) (即 成员变量是用来表示属性的,授课中,统一叫 属性
- 属性是类的一个组成部分,一般是基本数据类型,也可是引用类型(对象,数组)。比如我们前面定义猫类 的 int age 就 是属性
注意事项和细节说明
PropertiesDetail.java
1) 属性的定义语法同变量,示例:访问修饰符 属性类型 属性名;
这里老师简单的介绍访问修饰符: 控制属性的访问范围
有四种访问修饰符 public, proctected, 默认, private ,后面我会详细介绍
2) 属性的定义类型可以为任意类型,包含基本类型或引用类型
3) 属性如果不赋值,有默认值,规则和数组一致。具体说: int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
真正的对象是堆里面分配的空间(包括方法区的常量池),cat只是指向那个对象而已
Cat只是对象的引用(对象名而已)
例如小明不是一个人,只是个名字(代号)。真正的主体是生出来的那个玩意
类与对象
如何创建对象
1) 先声明再创建
Cat cat ; //声明对象 cat
cat = new Cat(); //创建
2) 直接创建
Cat cat = new Cat();
如何访问属性
基本语法
对象名.属性名;
案例演示赋值和输出
cat.name ;
cat.age;
cat.color;
类和对象的内存分配机制(重要)
Java 内存的结构分析
1) 栈: 一般存放基本数据类型(局部变量)
2) 堆: 存放对象(Cat cat , 数组等)
3) 方法区:常量池(常量,比如字符串), 类加载信息
4) 示意图 [Cat (name, age, price)]
Java 创建对象的流程简单分析
Person p = new Person();
p.name = “jack”;
p.age = 10
1) 先加载 Person 类信息(属性和方法信息, 只会加载一次)
2) 在堆中分配空间, 进行默认初始化(看规则)
3) 把地址赋给 p , p 就指向对象
4) 进行指定初始化, 比如 p.name =”jack”
看一个示例分析
成员方法
快速入门: Method01.java
为什么需要成员方法
Method02.java
看一个需求:
请遍历一个数组 , 输出数组的各个元素值。
解决思路 1,传统的方法,就是使用单个 for 循环,将数组输出,大家看看问题是什么
解决思路 2: 定义一个类 MyTools ,然后写一个成员方法,调用方法实现,看看效果又如何
5成员方法的好处
1) 提高代码的复用性
2) 可以将实现的细节封装起来,然后供其他用户来调用即可
方法的调用机制原理图 重要
提示:画出程序执行过程[getSum]+说明
注:上面的getSum栈是为了方便讲解取的名,实际在底层没有这种叫法
成员方法定义
访问修饰符 返回数据类型 方法名(形参列表..) {//方法体 语句; return 返回值; }
- 形参列表:表示成员方法输入 cal(int n) , getSum(int num1,)
2) 返回数据类型:表示成员方法输出, void 表示没有返回值
3) 方法主体:表示为了实现某一功能代码块
4) return 语句不是必须的。
5) 老韩提示: 结合前面的题示意图, 来理解
成员方法注意事项和使用细节(重要)
/chaper/ MethodDeatail.java、MethodDetail02.java
访问修饰符 (作用是控制 方法使用的范围)
如果不写默认访问,[有四种: public, protected, 默认, private], 具体在后面
返回数据类型
1) 一个方法最多有一个返回值 [思考,如何返回多个结果 返回数组 ]
2) 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
3) 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值; 而且要求返回值类型必须和 return 的
值类型一致或兼容
4) 如果方法是 void,则方法体中可以没有 return 语句,或者 只写 return
方法名
遵循驼峰命名法,最好见名知义,表达出该功能的意思即可, 比如 得到两个数的和 getSum, 开发中按照规
形参列表
- 一个方法可以有0个参数,也可以有多个参数,中间用逗号隔开,如: getSumI(int n ,int m)
- 参数类型可以为任意类型,包含基本类型或引用类型。比如 printArr(int[][] map)
- 调用带参数的方法时,一定要对应着参数列表传入相同类型或兼容类型的参数
- 方法定义是的参数为形式参数,简称形参;方法调用是的传入参数成为实际参数,简称实参,实参和形参的类型要一致或兼容、个数、顺序必须一致!
方法体
里面写完成功能的具体的语句,可以为输入、输出、变量、运算、分支、循环、方法调用,但里面不能在定义方法!
即:方法不能嵌套定义
方法调用细节说明(重要!)
MethodDetail02.java
- 同一个类中的方法调用:直接调用即可。比如:print(参数)
案例演示:A类sayOk 调用 print()
- 跨类中的方法A类调用B类方法:通过对象名调用。比如:对象名.方法名(参数);
案例演示:B类sayHello调用parint()
- 特别说明:跨类的方法调用和方法的访问修饰符相关。将到访问修饰符是回细说
成员方法传参机制(非常非常重要
基本数据类型的传参机制 chaper07/ MethodParameter01.java
结论:基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参
引用数据类型的传参机制 MethodParameter02.java
1) 看一个案例 MethodParameter02.java
B 类中编写一个方法 test100,可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化?会变化
B 类中编写一个方法 test200,可以接收一个 Person(age,sal)对象,在方法中修改该对象属性,看看原来的对象是否变化? 会变
结论及示意图
引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参!
//开辟了新的空间,包括保存字符串的常量池
//此时 p 就不再指向 main中的p 了
P = new Person
解读 : P = null是在方法体中执行,所以只是把方法体里的p置空, 不会影响到main中的p
在看一个案例,下面的方法会对原来的对象有影响吗?
p=null 和 p = new
形参为对象
方法递归调用
简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题,同时可以让代码变得简洁。
例子
阶乘问题
//factorial 阶乘
public int factorial(int n) {
if (n == 1) {
return 1;
} else {
return factorial(n - 1) * n;
}
}
打印问题
猴子吃桃问题 /chaper07/RecursionExercise01.java
猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!
以后每天猴子都吃其中的一半,然后再多吃一个。当到第 10 天时,
想再吃时(即还没吃),发现只有 1 个桃子了。问题:最初共多少个桃子?
递归重要规则
- 执行一个方法是,就创建一个新的受保护和独立空间(栈空间)。
- 方法的局部百年来是独立的,不会互相影响,比如上面阶乘中的n变量。
- 如果方阿飞中使用的是引用类型变量(如数组、对象),就会共享该引用类型的数据。
- 递归必须向退出递归的条件逼近,否则就是无限递归,(出现StackOverflowError,死龟了).
- 当一个方法执行完毕,或者遇到return, 就会返回,遵守谁调用,就将结果返回给谁, 同时当方法执行完毕或者返回时,该方法也就执行完毕.
方法重载
基本介绍
java 中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致
重载的好处
1) 减轻了起名的麻烦
2) 减轻了记名的麻烦
重载注意事项和使用细节
- 方法名:必须相同
- 形参列表:必须不同(形参类型 或 个数 或 顺序,至少有一样不同,参数名无要求)
- 返回类型:无要求
- 修饰符: 无要求
重载细节:
//传参: 实参 -> 形参 可以发生自动类型转换
// int -> double
System.out.println(s.max(10.3, 4.3,20));
但是反过来不可以
在匹配时, 优先匹配参数类型相同的(不用自动转换)
如:
public double max(double a, double b, double c)
public double max(double a, double b, int c)
可变参数
基本概念
java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。就可以通过可变参数实现。
基本语法
访问修饰符 返回类型 方法名(数据类型... 形参名) { }
注意事项和使用细节
- 可变参数的实参可以为0个或任意多个。
- 可变参数的实参可以为数组。
- 可变参数的本质就是数组。
- 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数放在最后。
- 一个形参列表中只能出现一个可变参数。
作用域
基本使用
面向对象中,变量作用域是非常重要知识点,相对来说不是特别好理解,请大家注
意听,认真思考,要求深刻掌握变量作用域。VarScope.java
1.在java编程中, 主要的变量就是属性(成员变量)和局部变量。
2.我们说的局部变量一般是指在成员方法中定义的变量。 [举例Cat类: cry]
3. java中作用域的分类
全局变量:也就是属性,作用域为整个类体Cat类: cry eat等方法使用属性
[举例]
局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中!
4.全局变量(属性)可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值。[举例]
作用域使用细节和注意事项(背)
- 属性和局部变量可以重名,访问时遵循就近原则。(或使用this 准确调用属性)
- 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。[举例]
- 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。即在一次方法调用过程中。
- 作用域范围不同
全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
局部变量:只能在本类中对应的方法中使用
- 修饰符不同
全局变量/属性可以加修饰符, 局部变量不可以加修饰符
构造方法/构造器
基本语法
[修饰符] 方法名(形参列表){
方法体;
}
老韩说明:
1) 构造器的修饰符可以默认, 也可以是 public protected private
2) 构造器没有返回值
3) 方法名 和类名字必须一样
4) 参数列表 和 成员方法一样的规则
5) 构造器的调用, 由系统完成
基本介绍
构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:
1) 方法名和类名相同
2) 没有返回值
3) 在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。
构造器使用细节和注意事项
ConstructorDetail.java
1.一个类可以定义多个不同的构造器,即构造器重载
比如:我们可以再给Person类定义一个构造器,用来创建对象的时候,只指定人名,不需要指定年龄
2.构造器名和类名要相同3.构造器没有返回值
4.构造器是完成对象的初始化,并不是创建对象
5.在创建对象时,系统自动的调用该类的构造方法
6.如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也
叫默认构造器),比如 Dog 00,使用javap指令反编译看看
7.一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无
参构造器,除非显式的定义一下,即:Dog(){ } 写(这点很重要)
8. 构造器复用: 在一个构造器中调用另外一个构造器.(注: 调用语句必须放在第一句, 故而只能调用一个构造器) 如
对象创建的流程分析(自己模拟画一遍)
this关键字
为了便于理解,可以认为每个对象创建过后都有一个隐藏的 this 指向它本身.
传统方法访问: 遵循就近原则
this访问: 直接访问属性
this 的注意事项和使用细节
ThisDetail.java
1) this 关键字可以用来访问本类的属性、方法、构造器
2) this 用于区分当前类的属性和局部变量
3) 访问成员方法的语法:this.方法名(参数列表);
4) 访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一条语句)
5) this 不能在类定义的外部使用,只能在类定义的方法中使用。
匿名对象
匿名对象
//老韩解读
// 1. new Homework08() 是匿名对象, 匿名对象使用后,就不能再使用了(因为没有指向他所以被销毁)
// 2. new Homework08().count1() 创建好匿名对象后,就调用count1
new Homework08().count1(); // 10
Homework08 t1 = new Homework08();
t1.count2(); // 9
t1.count2(); //10
八、面向对象编程(中级部分)
IDEA(集成开发环境)
模板/自定义模板
包
包的三大作用
- 区分相同名字的类。
- 当类很多时,可以很好的管理类【看java API 文档】
- 控制访问范围
包基本语法
包的本质分析(原理)
7常用的包
一个包下,包含很多的类,java 中常用的包有:
1) java.lang.* //lang 包是基本包,默认引入,不需要再引入. 2) java.util.* //util 包,系统提供的工具包, 工具类,使用 Scanner
3) java.net.* //网络包,网络开发
4) java.awt.* //是做 java 的界面开发,GUI
如何引入包
建议用那个类就引入哪个类。
包的注意事项和细节
PkgDetail.java
1. package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package
2. import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。
访问修饰符
基本介绍
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
- 公开级别:用 public 修饰,对外公开
- 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
- 默认级别:没有修饰符号,向同一个包的类公开.
- 私有级别:用 private 修饰,只有类本身可以访问,不对外公开.
四种访问修饰符的访问范围和注意事项( 重要 背下来)
●使用的注意事项
1)修饰符可以用来修饰类中的属性,成员方法以及类
2)只有默认的和public才能修饰类!,并且遵循上述访问权限的特点。
3)因为没有学习继承,因此关于在子类中的访问权限,我们讲完子类后,在回头讲解
4)成员方法的访问规则和属性完全一样.
/com.hspedu.modifier :
细节:
如果父类有 默认 修饰的属性, 按下图来说在子类中是无权限访问的,但如果此父类和子类在一个包内,子类依然可以直接访问父类的 默认属性
面向对象编程-封装
基本介绍
封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。
封装的理解和好处
1)隐藏实现细节:方法(连接数据库)<--调用(传入参数..
2)可以对数据进行验证,保证安全合理
Person {name, age}
Person p = new Person);p.name = "jack" ;
p.age = 1200;//明显不合理
封装的实现步骤(三步)
1)将属性进行私有化private【不能直接修改属性】
2)提供一个公共的(public)set方法,用于对属性判断并赋值
public void setXxx(类型参数名)//Xxx表示某个属性
1/加入数据验证的业务逻辑
属性=参数名;
}
3)提供一个公共的(public)get方法,用于获取属性的值public 数据类型getXxx(){//权限判断,Xxx某个属性
return xx;
}
将构造器和 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);
}
面向对象编程-继承(extends)
为什么需要继承
继承基本介绍和示意图
继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中
抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。画出继承的示意图
Extends 关键字不能去掉
继承的基本语法
继承给编程带来的便利
1) 代码的复用性提高了
2) 代码的扩展性和维护性提高了
继承的深入讨论/细节问题(重要)
1) 子类继承了父类所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
2) 子类必须调用父类的构造器, 完成父类的初始化
3) 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 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 的逻辑关系
可以说他两个可以抽象出共同特征, 如: 小狗是动物, 小学生是人
继承的本质讨论 / 子类创建的内存布局(重要)
继承的本质就是建立一个 查找关系
//?-> 这时请大家注意,要按照查找关系来返回信息
//(1) 首先看子类是否有该属性
//(2) 如果子类有这个属性,并且可以访问,则返回信息
//(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object...
细节
如果father 类中有 private int age; gradePa类有 public int age;
//调用本类中的没有的属性,会严格按照查找关系来返回信息
//比如此例:调用age时,首先看本类里没有->找父类里的age : 无访问权限
// 之后就是GrandPa类中有 public int age 也不会在往上找了,会直接在父类那儿报错
System.out.println(son.age);
报错信息
'age' has private access in 'com.hspedu.extend_.Father'
子类创建的内存布局
查找属性和方法:都是按照加载类信息顺序相反的方向找的
super除了第一步直接从父类里面查找,其余逻辑一样
super关键字
基本介绍
super 代表父类的引用,用于访问父类的属性、方法、构造器。
基本语法 package com.hspedu.super_ super01
1.访问父类的属性,但不能访问父类的private属性[案例]
super.属性名;
2.访问父类的方法,不能访问父类的private方法
super.方法名(参数列表);
3.访问父类的构造器(这点前面用过):
super(参数列表);只能放在构造器的第一句,只能出现一句!
细节
//super 的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用 super 去访问爷爷类的成员; // 如果多个基类(上级类)中都有同名的成员,使用 super 访问遵循就近原则。A->B->C
//找 cal 方法时(cal() 和 this.cal()),顺序是:
// (1)先找本类,如果有,则调用
// (2)如果没有,则找父类(如果有,并可以调用,则调用)
// (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object 类
// 提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
cal() 等价于 this.cal()
//super.cal() 的顺序是直接查找父类,其他的规则一样
//super.cal()
访问属性时规则亦相同
super 给编程带来的便利/细节
/SuperDetail.java
1.调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果![举例]
3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super 访问时遵循就近原则。A -> B -> C,当然也需要遵守访问权限的相关规则。
Super和 this 的比较
方法重写/覆盖(override)
基本介绍
简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法。
参见:
package com.hspedu.override_ Animal.java Dog.java
注意事项和使用细节
方法重写也叫方法覆盖,需要满足下面的条件