Java基础复习笔记详细版
Posted Refeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础复习笔记详细版相关的知识,希望对你有一定的参考价值。
Java基础复习笔记
第01章:Java语言概述
1. Java基础学习的章节划分
第1阶段:Java基本语法
Java语言概述、Java的变量与进制、运算符、流程控制语句(条件判断、循环结构)、break\\continue、
IDEA开发工具的使用、数组
第2阶段:面向对象编程(基础、进阶、高级)
第3阶段:Java高级应用
异常处理、多线程、集合框架、File类与IO流、网络编程、日期相关的API与比较器、反射、Java8-17新特征
语言 = 语法 + 逻辑
2. 计算机的构成
- 硬件:CPU、内存、硬盘、输入设备、输出设备、调制解调器
- 软件
3. 软件
- 软件:即一系列按照
特定顺序组织
的计算机数据
和指令
的集合。- 有系统软件和应用软件之分。
- 系统软件:windows、mac os、android、ios、linux
- 应用软件:qq、微信、音乐播放器等
- 有系统软件和应用软件之分。
4. 人机交互方式
-
图形化界面的方式
-
命令行的方式交互
-
DOS命令(掌握)
- cd cd.. cd/ md rd del exit cls等
5. 语言
-
计算机语言的分代
- 第1代:机器语言:0和1
- 第2代:汇编语言:出现了助记符
- 第3代:高级语言:
- 面向过程阶段:C
- 面向对象阶段:C++,Java,C#,Python,JS等
-
没有“最好”的语言,只有在特定场景下相对来说,最适合的语言而已。
6. Java概述
-
Java简史
- 1995诞生
- 1996:jdk1.0版本
- 2004:Java5.0(jdk1.5)--->里程碑式的版本;J2SE->JavaSE、J2EE->JavaEE、J2ME->JavaME
- 2014:Java8.0--->里程碑式的版本;目前,市场占有率仍然很高。(lambda表达式、StreamAPI)
- 后续:Java11、Java17都属于LTS(长期支持版本)
-
SUN、Oracle、Google等
-
Java之父:詹姆斯·高斯林
-
Java的应用场景:
- JavaSE:开发桌面级应用 (不靠谱)
- JavaEE:开发企业级后台应用
- JavaME:开发小型设备的应用(不靠谱)
----> JavaEE、Android应用、大数据开发
7. JDK的下载、安装及环境变量的配置(重点)
- jdk下载:官网下载
- 安装:jdk8.0和jdk17.0 (傻瓜式安装)
- path环境变量的配置(重点)
8. 第1个Java程序
新建java文件:PersonInfo.java
class PersonalInfo
public static void main(String[] args)
System.out.println("姓名:家琪琪\\n");
//System.out.println();//换行操作
System.out.println("性别:女");
System.out.println("住址:成都青创园");
针对于第1个程序的小结及常见问题的分析
1. HelloWorld程序如下:编写在HelloWorld.java文件中
class HelloJava
public static void main(String[] args)
System.out.println("HelloWorld!!");
System.out.println("HelloWorld!!");
System.out.println("你好,世界!");
2. Java程序要想执行成功,需要如下的三个步骤:
第1步:编写:将java源代码编写在.java结尾的源文件中。
第2步:编译:针对于编写好的源文件进行编译操作。格式:javac 源文件名.java
编译以后,会生成一个或多个.class结尾的字节码文件。字节码文件的名称即为源文件中对应的类名
第3步:运行:针对于编译好的字节码文件,进行解释运行操作。格式: java 字节码文件名 或 java 类名
3. 针对于编写过程来说:
3.1 class:是一个关键字,小写,后面跟着一个类名。
3.2 编写的类或方法必须使用一对。
3.3
> main()作为程序的入口出现!格式如下:
public static void main(String[] args)
> main()的格式是固定的!大家刚开始学习,可以"死记硬背"一下。
> 但是,可以考虑修改为如下的格式:
方式1:public static void main(String args[])
方式2:public static void main(String[] a) args:是arguments的缩写
3.4 输出语句的编写:
> System.out.println(123); 表示:输出123之后换行
> System.out.print(123); 表示:输出123之后不需换行
3.5 编译过程中的小结:
> 编译源文件。此时要求在源文件所在的路径下执行"javac 源文件名.java"的操作
可能编译时报错的情况:
情况1:如果源文件名写错(不包括大小写不同的情况)或者不是在源文件所在的路径下执行javac操作则会报错。
情况2:编写的程序中有非法的语法或非法的字符。
> 缺少必要的大括号、大小写的问题(Java是严格区分大小写的)、出现的标点符号必须是英文格式下的
3.6 解释运行过程的小结:
> 针对于字节码文件对应的类,执行java.exe命令。格式:java 类名。
> 此操作需要在字节码文件所属的路径下执行。
可能运行时报错的情况:
情况1:执行字节码文件所在的路径不对或字节码文件的名写错了(注意,java严格区分大小写,如果大小写出错了,仍然认为文件名写错了)。
情况2:可以出现运行时异常(放到第9章中讲解)
3.7 说明
1. Java是严格区分大小写的
2. 每一行执行语句必须以;结尾
3. 程序在编写过程中,为了可读性更强,增加必要的缩进,使用tab键即可。
4. 一个源文件中可以声明一个或多个类。
一个源文件中最多只能有一个类声明为public。
声明为public的类的类名必须与源文件名相同。
9. 注释
- 掌握:单行注释、多行注释
- 作用1:对程序中的代码进行解释说明
- 作用2:有助于调试程序
- 熟悉:文档注释 (可以被javadoc解析)
10. API文档
- API:(Application Programming Interface,应用程序编程接口)是 Java 提供的基本编程接口。
- 像String、System都属于API
- API文档:用于解释说明API如何使用的一个文档。
第02章:变量与进制
1. 关键字(keyword)
- 关键字:被Java语言赋予特殊含义的字符串。
- 注意点:关键字都是小写的!
- Java规范了50个关键字(包含了goto、const两个保留字)
- 额外的三个字面量true、false、null虽然不是关键字,但是我们也把他们看做是关键字。
2. 标识符
- 凡是可以自己命名的地方,都是标识符。
- 标识符都有哪些位置?类名、变量名、包名、方法名、接口名、常量名等
- 标识符的命名规则
(如果不遵守,编译不通过。要求大家遵守)
由26个英文字母大小写,0-9 ,_或 $ 组成
数字不可以开头。
不可以使用关键字和保留字,但能包含关键字和保留字。
Java中严格区分大小写,长度无限制。
标识符不能包含空格。
- 标识符的命名规范
(如果不遵守规范,不影响程序的编译和运行。建议大家遵守,否则容易被鄙视)
包名:多单词组成时所有字母都小写:xxxyyyzzz。
例如:java.lang、com.atguigu.bean类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz
例如:HelloWorld,String,System等变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz
例如:age,name,bookName,main,binarySearch,getName常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ
例如:MAX_VALUE,PI,DEFAULT_CAPACITY
- 标识符在声明时,要见名知意!
3. 变量的基本使用
- 内存中的一个存储区域,该区域的数据可以在同一类型范围内不断变化
- 变量的构成包含三个要素:数据类型 变量名 变量值
- Java中变量声明的格式:数据类型 变量名 = 变量值;
- Java是一门强类型的语言。即每一个变量都规定了具体的类型。
- 使用变量注意:
- Java中每个变量必须先声明,后使用。
- 使用变量名来访问这块区域的数据。
- 变量的作用域:其定义所在的一对 内。
- 变量只有在其作用域内才有效。出了作用域,变量不可以再被调用。
- 同一个作用域内,不能定义重名的变量。
4. 基本数据类型的变量
变量按照数据类型来分:
基本数据类型:整型(byte \\ short \\ int \\ long ) 、浮点型(float \\ double ) 、字符型char 、布尔型boolean
引用数据类型:类(class)、接口(interface)、数组(array); 注解(annotation)、枚举(enum)、记录(record)
- 整型变量
//1. 整型的使用:
//byte(1个字节=8bit,-128~127) \\ short(2字节) \\ int(4字节) \\ long(8字节)
byte b1 = 12;
b1 = 127;
//①声明变量以后,给变量赋的值必须在变量类型所允许的范围内变化。
//b1 = 128;//因为超出了byte的范围,所以报错
//② 给long类型变量赋值时,要求以"l"或"L"结尾
short s1 = 123;
int i1 = 1234;
long l1 = 12313123L;
System.out.println(l1);
//③ 实际开发中,如果没有特殊需求的话,推荐大家使用int类型来定义整型变量。
//④ 默认情况下,整型常量都是int类型
//int i2 = i1 + 2;
- 浮点类型
//2. 浮点型的使用:
// float(4字节) / double (8字节)
//① float虽然占用的空间比long小,但是表数范围比long大,进而float精度不高。
//② 给float类型变量赋值时,要求以"f"或"F"结尾。否则,编译不通过
double d1 = 123.456;
//d1 = 123.456456456456456456; //体会double的精度也有限
System.out.println(d1);
float f1 = 123.456f;
System.out.println(f1);
//③ 实际开发中,如果没有特殊需求的话,推荐大家使用double类型来定义浮点型变量。
//④ 默认情况下,浮点型常量都是double类型
double d2 = d1 + 12.34; //12.34是常量,是double类型
- char类型(字符类型)
//3.字符类型的使用:char (2字节)
//① 一般情况下,我们使用一对\'\'表示一个具体的字符。
//说明:char定义变量的话,\'\'内有且只能有一个字符
char c1 = \'a\';
//编译不通过
//char c2 = \'\';
//char c3 = \'ab\';
//② char类型变量的定义方式
//方式1:最常见的方式
char c4 = \'中\';
char c5 = \'1\';
char c6 = \'す\';
//方式2:直接使用Unicode值来表示字符型常量
char c7 = \'\\u0023\';
System.out.println(c7);
//方式3:使用转义字符
char c8 = \'\\n\';
char c9 = \'\\t\';
System.out.println("hello" + c8 + "world");
System.out.println("hello" + c9 + "world");
//方式4:使用字符对应的ascii码值进行赋值
char c10 = \'a\';
System.out.println(c10 + 1);
char c11 = 97;
System.out.println(c10 == c11);//true
- 布尔类型(boolean)
//① 不谈boolean占用内存空间的大小
//② boolean类型只能取两个值之一:true 、 false
boolean b1 = true;
boolean b2 = false;
//③ 开发中,我们常常在if-else结构、循环结构中使用boolean类型
boolean isMarried = false;
if(isMarried)
System.out.println("很遗憾,不是单身了");
else
System.out.println("不错,可以多谈几个女朋友了");
5. 基本数据类型变量间的运算规则
5.1 自动类型提升规则
byte、short、char ---> int ---> long ---> float ---> double
说明:
① 容量小的变量和容量大的变量做运算时,运算的结果是容量大的变量的数据类型。
(此时的容量小、容量大指的是存储数据的范围的大小,并非占用内存空间的大小。比如:float的容量要大于long的容量)
② byte、short、char 三者之间的变量做运算,结果是int类型。
③ 不管是自动类型提升规则,还是强制类型转换规则都只针对于基本数据类型中的7种进行操作(除了boolean类型)
5.2 强制类型转换规则
说明:
①看做是自动类型提升规则的逆运算
② 如果需要将容量大类型的变量转换为容量小的类型的变量时,就需要使用强制类型转换
③ 强制类型转换需要使用一对()表示
④ 使用强转符转换时,可能造成精度的损失
6. String与8种基本数据类型变量间的运算
- String的理解
String,即为字符串类型。
声明String类型的变量,可以使用一对""表示。
一对""内可以声明0个、1个或多个字符
- String与基本数据类型变量间的运算
String类型是可以与8种基本数据类型的变量做运算的。
String只能与8种基本数据类型的变量做连接运算:+
连接运算的结果只能是String类型。
7. 进制(了解)
- 计算机中存储和运算的
所有数据
都要转为二进制
。包括数字、字符、图片、声音、视频等。
7.1 常见的几种进制
-
熟悉:
-
十进制(decimal)
- 数字组成:0-9
- 进位规则:满十进一
-
二进制(binary)
- 数字组成:0-1
- 进位规则:满二进一,以
0b
或0B
开头
-
八进制(octal):很少使用
- 数字组成:0-7
- 进位规则:满八进一,以数字
0
开头表示
-
十六进制
- 数字组成:0-9,a-f
- 进位规则:满十六进一,以
0x
或0X
开头表示。此处的 a-f 不区分大小写
-
7.2 二进制与十进制间的转换
熟悉:二进制与十进制间的转换(见ppt)
-
表示二进制整数时,最高位为符号位。0:正数;1:负数。
-
二进制整数在存储时,涉及到原码、反码、补码。
-
正数:三码合一。
-
负数:负数的原码,除符号位外,各个位取反,得到负数的反码。
负数的反码+1,得到负数的补码。
-
-
计算机底层都是以二进制
补码
的形式存储数据的。
7.3 二进制与其它进制间的转换
- 了解:二进制与八进制、十六进制间的转换
第03章:IDEA的安装与使用
1. 认识IDEA的地位、特点
- Java开发中占比第1。
- Eclipse?IDEA?① 符合人体工程学 ② 功能强大
2. IDEA的下载、安装、注册
略
3. IDEA的基本使用
- 在IDEA中能创建一个工程:Project。
- 在工程的src下写一个HelloWorld,并运行
- 安装课件中的第5节中的设置,作必要的修改。
4. 熟悉工程、module中jdk和设置语言级别操作
关于工程:
关于Module:
添加SDK:
5. 熟悉Project-Module-Package-Class的关系
- 上一级和下一级之间是一对多的关系。
- 掌握:新建Project、新建Module、删除Module、导入老师的Module(难点)
6. 关于IDEA的其它操作
- 模板的使用
- 快捷键的使用
- Debug程序
- 插件的使用
第04章:运算符与流程控制
1. 运算符之1:算术运算符
+ - + - * / % ++ -- +
- % : 结果与被模数的符号相同。常用来判别是否能整除一个数。
- (前)++ 与 (后)++ ;(前)-- 与 (后)--
2. 运算符之2:赋值运算符
= += -= *= /= %=
- = : 与 == 的区别。= 的右边是变量或常量。"连续赋值" (int i,j;i = j = 10;)
- += -= *= /= %= :运算后,不会改变变量的类型。(int i = 1; i *= 0.1; )
3. 运算符之3:比较运算符
> < >= <=
== !=
> < >= <=
只能适用于7种基本数据类型(不含boolean)== !=
适用于8种基本数据类型、引用数据类型。- 比较运算符的结果是boolean类型。
4. 运算符之4:逻辑运算符
& && | || ^ !
- 逻辑运算符操作的是boolean类型,结果也是boolean类型
- & 与 && 的区别;| 与 || 的区别
5. 运算符之5:位运算符(非重点)
<< >> >>>
& | ^ ~
- 位运算符操作的整数类型
- << >> >>>的应用场景
6. 运算符之6:条件运算符
(条件表达式)? 表达式1 : 表达式2
规则:
判断条件表达式是true还是false,如果是true,则执行表达式1;如果是false,则执行表达式2
如果将运算的结果赋给一个变量的话,要求:表达式1与表达式2的类型一致。(相同 或 满足自动类型提升的规则即可)
- 案例:获取两个数的较大值;获取三个数的最大值
- 与分支结构的if-else对比:
凡是可以使用条件运算符的地方,都可以改写为if-else。反之,不一定。
在既可以使用条件运算符,又可以使用if-else的场景下,推荐使用条件运算符。因为条件运算符效率稍高。
7. 运算符的优先级
-
我们在开发中,如果希望某个运算符优先运算的话,主动的添加一对()。
-
常见的一些运算符优先级谁高谁低呢?基本上是
如你所想
。int x = 10; boolean y = false; if(x++ == 10 && y = true)...
-
大家在开放时,如果涉及到多个运算符做运算,建议可以
分行写
。
8. 流程控制语句概述
顺序结构:略,即代码从上往下依次执行
分支结构:if-else 、 switch-case
循环结构:for、while、do-while
foreach放到集合章节中讲解
9. 分支结构1:if-else
- 格式
格式1:
if(条件表达式){
语句块;
}
格式2:"二选一"
if(条件表达式)
语句块1;
else
语句块2;
格式3:"多选一"
if (条件表达式1)
语句块1;
else if (条件表达式2)
语句块2;
...
else if (条件表达式n)
语句块n;
else
语句块n+1;
- 说明
说明1:
> 如果多个条件表达式之间是"互斥"关系(或没有交集的关系),则多个条件表达式谁写在上面,谁写在下面都可以。
> 如果多个条件表达式之间是包含关系,则通常需要将条件表达式范围小的声明在条件表达式范围大的上面。
说明2:
> 我们可以在程序使用if-else的嵌套结构
> 如果if-else中一对大括号内的语句块只有一行执行语句,则此一对大括号可以省略。但是,不建议大家省略!
说明3:
> 开发中,在一些具体的题目中,可以在if-else if -else if -... -else 结构中省略else结构。
10. 分支结构2:switch-case
- 格式
switch(表达式)
case 常量值1:
语句块1;
//break;
case 常量值2:
语句块2;
//break;
// ...
[default:
语句块n+1;
break;
]
- 说明
1. switch-case的执行过程:
根据switch中表达式的值,依次匹配一对内的case结构。一旦表达式与某个case的常量值相等,则执行此case中的语句块。
执行完此语句块之后,如果此case中包含break,则结束当前switch-case结构。
如果此case中不包含break,则会继续执行其后的case中的语句块(case穿透的场景)。直到遇到break或执行完default,才会结束switch-case结构。
2. 说明:
> 在switch-case结构中可以使用break关键字,一旦执行,表示终止(或退出)当前switch-case结构。
> 开发中,在使用switch-case的场景中,不加break的情况要多于加break的情况。
> switch中的表达式只能是特定的如下类型的变量:
byte \\ short \\ char \\ int ; 枚举类型(jdk5.0新增) \\ String(jdk7.0新增)
> case后的常量值,需要与switch中表达式的值进行==的判断。如果返回true,则执行此case中的语句块。返回false,则不执行。
> default类似于if-else结构中else。 可选的,且位置是灵活的。
- if-else 与 switch-case的对比
> 针对的变量的类型来讲,if-else没有限制,而switch-case有类型的限制,且建议case匹配的情况有限、不多的场景。
> 二者的转换:凡是使用switch-case结构的,都可以转换为if-else。反之,不成立。
> 开发中,在既可以使用switch-case,又可以使用if-else的情况下,推荐使用switch-case。因为其效率稍高。
> if-else的主要优势:涉及到任何的分支结构,都可以使用if-else实现
switch-case的主要优势:在可以使用if-else和switch-case的情况下,效率稍高。
case穿透。
11. 循环结构1:for
- 循环的概述
凡是循环结构,都有如下的4个要素:
> ① 初始化条件部分
> ② 循环条件部分 -->是boolean类型
> ③ 循环体部分
> ④ 迭代条件部分
- 格式
for(①;②;④)
③
执行过程:① - ② - ③ - ④ - ② - ③ - ④ - ...- ②
- 说明
1. 注意:循环条件部分必须是boolean类型。
2. break关键字的使用
> break可以使用在循环结构中 (复习:还可以使用在switch-case中)
> 一旦执行,就跳出当前循环结构。
12. 循环结构2:while
- 格式
①
while(②)
③
④
- 执行过程
① - ② - ③ - ④ - ② - ③ - ④ - ...- ②
- 说明
for循环和while循环一定可以相互转换。
for、while循环的区别:初始化条件的作用域不同。while循环的初始化条件在while循环结束后,仍然有效。
13.循环结构3:do-while
- 格式
①
do
③
④
while(②);
- 执行过程
① - ③ - ④ - ② - ③ - ④ - 。。。- ②
- 说明
do-while相较于其他循环的区别:至少执行一次循环体。
在循环条件第1次判断时,如果是true的情况下,三个循环结构可以相互转换的。
- 使用场景
for循环:有明确的循环、遍历次数时。比如:遍历100以内的自然数、遍历数组
while循环:没有明确的循环、遍历的次数时。比如:使用迭代器遍历集合。
do-while循环:确保至少执行一次。
14. "无限"循环
- 结构
while(true) 、 for(;;)
- 使用场景
不确定循环的次数时,使用此结构
- 结束循环的方式
在循环内部,满足某个条件的情况下,执行break。
- 注意:必须确保此循环可以结束。否则就是死循环!我们开发中要避免死循环
15. 嵌套循环
- 格式
外层循环
内层循环
-
说明:上述的外层循环、内存循环可以是for、while、do-while
-
技巧:
- 外层循环执行m次,内层循环执行n次。意味着内层循环的循环体执行 m * n次
- 外层控制行数,内层控制列数
16. break、continue关键字的使用
相同点:① 都可以使用在循环结构中 ② 其后不能编写执行语句
不同点:① 结束循环结构;结束当次循环 ②使用范围:break:switch-case结构中使用
17. Scanner的使用、随机数的获取
- Scanner的使用
1. 如何从键盘获取数据? 使用Scanner类
2. 如何使用Scanner类,从键盘获取数据呢? (掌握)
步骤1:导包
import java.util.Scanner
步骤2:创建Scanner的对象(或实例)
Scanner scanner = new Scanner(System.in);
步骤3:通过Scanner的对象,调用Scanner类中声明的方法,从键盘获取指定类型的变量
scanner.nextXxx()
步骤4:关闭Scanner
scanner.close();
3. Scanner类中提供了如下的获取不同类型变量的方法:
获取byte: nextByte();
获取short: nextShort();
获取int: nextInt();
获取long: nextLong();
获取float: nextFloat();
获取double: nextDouble();
获取boolean: nextBoolean();
注意,没有提供获取字符的方法。我们可以通过获取字符串的方法,来获取字符。
获取String: next() / nextLine()。
如何获取一个字符:next().charAt(0)
- 如何获取随机数
1. 调用Math类中的random(),可以获取一个[0.0,1.0)范围内的随机浮点数。
2. 如何获取[0,9]范围的随机整数:(int)(Math.random() * 10);
如何获取[1,10]范围的随机整数:(int)(Math.random() * 10) + 1;
如何获取[0,100]范围的随机整数:(int)(Math.random() * 101);
如何获取[10,100]范围的随机整数:(int)(Math.random() * 91) + 10; //[10,100]
公式:如何获取[a,b]范围的随机整数:(int)(Math.random() * (b - a + 1) + a)
18. 阶段项目1:谷粒记账软件
略
第05章:数组
1. 数组的概述(理解)
1. 数组的理解
概念:
数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,
并通过编号的方式对这些数据进行统一管理。
简称:多个相同类型的数据的组合
Java中的容器:数组、集合框架(用于存储不同特点的多个数据)
2. 几个相关的概念
> 数组名(即为容器的名称)
> 元素 (即为数组中具体的一个个的数据)
> 数组的长度(容器中元素的个数)
> 数组的角标、下标、下角标、索引、index (即为数组中元素的具体位置。从0开始)
3. 数组的特点:
- 数组本身是`引用数据类型`,而数组中的元素可以是`任何数据类型`,包括基本数据类型和引用数据类型。
- 创建数组对象会在内存中开辟一整块`连续的空间`。占据的空间的大小,取决于数组的长度和数组中元素的类型。
- 数组中的元素在内存中是依次紧密排列的,有序的。
- 数组,一旦初始化完成,其长度就是确定的。
- 数组的`长度一旦确定,就不能修改`。
- 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
- 数组名中引用的是这块连续空间的首地址。
4. 复习:变量按照数据类型的分类
4.1 基本数据类型:byte \\ short \\ int \\ long ;float \\ double ;char ;boolean
4.2 引用数据类型:类、数组、接口; 枚举类型、注解类型、记录类型(Record)
5. 数组的分类
5.1 按照元素的类型:基本数据类型元素的数组、引用数据类型元素的数组
5.2 按照数组的维数来分:一维数组、二维数组、....
2. 一维数组的使用(重点)
(6个基本点)
> 数组的定义:静态初始化、动态初始化
> 数组元素的表示:使用角标,角标从0开始,到数组的长度-1结束。
> 数组的长度:length
> 遍历数组:for循环
> 数组元素的默认值:记住。后续类中属性的默认值也如此。
> 数组的内存解析(难点)---> 具体图示见chapter06章节的module中即可。
3. 二维数组的使用(熟悉)
- 二维数组的理解
> 角度1:一个一维数组又作为了另一个数组arr的元素。则数组arr就称为二维数组。
> 角度2:一个数组arr1的元素,仍是是一个数组,则arr1称为二维数组
> 数组,属于引用数据类型;数组的元素也可以是引用数据类型。--> 数组的元素,还可以是数组。
> 说明:其实Java中不存在二维、三维、..数组,只是将一个上述的arr或arr1称为是二维数组。
> 区分:外层元素、内层元素
- 基本内容
二维数组的使用(6个基本点)
> 数组的定义
> 数组元素的调用
> 数组的长度
> 数组的遍历
> 数组元素的默认初始化值(稍难)
> 数组的内存解析(难点)---> 具体图示见chapter06章节的module中即可。
- 数组元素的默认值
1. 二维数组元素的默认初始化值
1.1 动态初始化方式1:(比如:int[][] arr = new int[3][4])
外层元素:存储的是地址值。(具体来说,就是外层元素指向的一维数组的地址值)
内层元素:与一维数组元素的默认值相同。
> 整型:0
> 浮点型:0.0
> 字符型:0 或 \'\\u0000\'
> 布尔型:false
> 引用类型:null
1.2 动态初始化方式2:(比如:int[][] arr = new int[3][])
外层元素:null
内层元素:不存在。一旦调用会报异常(NullPointerException)
4. 数组的常用算法(熟练)
- 算法常用操作1
1. 数值型数组特征值统计
这里的特征值涉及到:平均值、最大值、最小值、总和等
2. 数组元素的赋值(实际开发中,遇到的场景比较多)
3. 数组的复制、赋值
4. 数组的反转
- 算法常用操作2
1. 数组的扩容与缩容
2. 数组元素的查找(或搜索)
顺序查找:
> 优点:简单,好理解,数组没有任何的前提限制。(比如:有序)
> 缺点:相较于二分法查找更慢一些。
二分法查找:
> 优点:相较于顺序查找,更快。O(logN)
> 缺点:必须此数组有序。
3. 排序算法
3.1 排序算法的衡量标准:
> 时间复杂度:更为关心的标准。
Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n^2)<Ο(n^3)<…<Ο(2^n)<Ο(n!)<O(n^n)。
> 空间复杂度:常出现以空间换时间的做法。
> 稳定性
3.2 排序的分类:内部排序、外部排序
内部排序的具体算法:十种。
我们需要关注的几个排序算法:
> 冒泡排序:简单、容易实现;企业笔试中容易考。时间复杂度:O(n^2)。要求大家可以手写。
> 快速排序:快速、开发中需要排序情况下的首选。时间复杂度:O(nlogn)。要求大家至少可以说明其实现思路。
5. Arrays:数组的工具类(熟悉)
1. Arrays类所在位置
java.util.Arrays
2. 作用:
封装了针对数组的常用操作。比如:排序、二分查找、比较数组是否相等、遍历等。
3. 常用方法:
sort(int[] arr) / binarySearch(int[] arr,int target) / toString(int[] arr)
6. 小结:数组中的常见异常
1. 数组的使用中常见的异常小结
> ArrayIndexOutOfBoundsException:数组角标越界异常
> NullPointerException:空指针异常
2. 出现异常会怎样?如何处理?
> 一旦程序中出现异常,且没有处理的情况下,程序就终止执行。
> 目前大家编程时,如果出现上述异常。回来根据异常的提示,修改代码,确保后续运行不再出现。
第06章:面向对象-基础
面向对象内容的三条主线:
> 类及类的内部成员:属性、方法、构造器;代码块、内部类
> 面向对象的三大特征:封装性、继承性、多态性
> 其它关键字的使用:package、import、this、super、static、final、abstract、interface等
1. 理解:面向过程vs面向对象
简单的语言描述二者的区别
> 面向过程:以`函数`为组织单位。是一种“`执行者思维`”,适合解决简单问题。扩展能力差、后期维护难度较大。
> 面向对象:以`类`为组织单位。是一种“`设计者思维`”,适合解决复杂问题。代码扩展性强、可维护性高。
2.2 二者关系:在面向对象的编程中,具体的方法中,仍然会体现面向过程的思想。所以二者是合作关系。
2. 面向对象的要素:类、对象
-
区分类与对象
- 类:抽象的、概念上的定义
- 对象:具体的,实实在在存在的,由类派生出来的
-
设计类,就是设计类的成员:属性、方法
-
面向对象完成具体功能的操作的三步流程(非常重要)
步骤1:创建类,即设计类的内部成员(属性、方法) 步骤2:创建类的对象。 步骤3:通过"对象.属性" 或 "对象.方法"的方式,完成相关的功能。
-
对象的内存解析
- JVM内存分配:虚拟机栈、堆、方法区(目前用不到)、程序计数器(略)、本地方法栈(略)
- 虚拟机栈:存放的是方法对应的栈帧,每个栈帧中存放方法中声明的局部变量。
- 堆:new出来的"东西":数组实体、对象实体(含成员变量)
- 创建类的1个对象、创建类的多个对象(内存解析图建议大家都自己画画)
- JVM内存分配:虚拟机栈、堆、方法区(目前用不到)、程序计数器(略)、本地方法栈(略)
3. 类的成员之一:属性(重点)
1.变量的分类:
- 角度一:按照数据类型来分:基本数据类型(8种)、引用数据类型(数组、类、接口;注解、枚举、记录)
- 角度二:按照变量在类中声明的位置来分:成员变量、局部变量
2. 成员变量的几个称谓:
成员变量 <=> 属性 <=> field(字段、域)
3. 区分成员变量 vs 局部变量
3.1 相同点:(了解)
> 都有三个要素(数据类型、变量名、变量值)
> 声明的格式相同:数据类型 变量名 = 变量值
> 变量都是先声明后使用
> 变量都有作用域,在其作用域内是有效的
3.2 不同点:
① 类中声明的位置的不同:
> 成员变量:声明在类内部、方法等结构的外部。
> 局部变量:声明在方法内部、方法的形参、构造器的内部、构造器的形参、代码块的内部等
② 在内存中分配的位置不同:
> 成员变量:随着对象实体在堆空间进行分配而分配(或存储)
> 局部变量:存储在栈空间。
③ 生命周期:
> 成员变量:随着对象的创建而产生,随着对象的消亡而消亡
> 局部变量:(以方法为例)随着方法的调用而产生,随着方法的调用结束而消亡。
> 拓展:每一个方法的执行,都对应着一个栈帧加载进栈中。局部变量就存储在每个方法对应的栈帧中。
当方法执行结束时,对应的栈帧就弹出栈,进而栈帧中的局部变量也弹出,进而消亡。
④ 作用域:
> 成员变量:在整个类的内部是有效的。---> 类的方法中是可以调用类中的成员变量的。
> 局部变量:以方法为例,作用域仅限于方法内部。
⑤ 是否可以有权限修饰符进行修饰:(超纲)
> 成员变量:可以被不同的权限修饰符进行修饰。(后面讲封装性时,具体说:private、public、protected、缺省)
> 局部变量:不可以被权限修饰符进行修饰。一旦修饰,编译不通过。
⑥ 是否有默认值:
> 成员变量:都有默认值
默认值的情况与不同类型的一维数组的元素的默认值相同。
> 整型:0
> 浮点型:0.0
> 字符型:0
> 布尔型:false
> 引用类型:null
> 局部变量:没有默认值。
意味着在调用之前必须要显示赋值。如果不赋值,就报错。
> 特别的:方法的形参在方法调用时赋值即可。
4. 类的成员之二:方法(重点)
4.1 方法的使用
1. 使用方法的好处
将功能封装为方法的目的是,可以实现代码重用,减少冗余,简化代码。
2. 使用举例
- Math.random()的random()方法
- Math.sqrt(x)的sqrt(x)方法
- System.out.println(x)的println(x)方法
- new Scanner(System.in).nextInt()的nextInt()方法
- Arrays类中的binarySearch()方法、sort()方法、equals()方法
3. 方法声明的格式
举例:public void eat()
public void sleep(int hour)
public String getName()
public String playGame(String game)
格式:
权限修饰符 返回值类型 方法名(形参列表)
方法体
4. 具体的方法声明的细节
4.1 权限修饰符:体现此方法被调用时,是否能被调用的问题。(主要放到封装性的时候讲解)
暂时,大家在声明方法时,先都使用public修饰即可。
4.2 返回值类型:(难点)
> 分类:有具体的返回值的类型(指明具体的数据类型) 、 没有返回值类型(使用void)
> 情况1:有具体的返回值的类型的要求:既然有返回值的类型,则要求此方法在执行完时,一定要返回
满足此类型的一个变量或常量。
> 内部使用"return 变量(或常量)"的方法,返回数据
> 情况2:没有返回值类型:内部就不需要使用return结构了。
> (难点)其实,我们在此方法中也可以使用return,仅表示结束此方法。
开发中,设计一个方法时,是否需要设计返回值类型?
> 根据题目的要求设计。
> 具体问题具体分析:调用完此方法之后,是否需要一个结果性的数据,供之后使用。如果有必要,就设计有返回值类型的场景即可。
4.3 方法名:属性标识符,定义时需要满足标识符的命名规则、规范、"见名知意"。
4.4 形参列表:(难点)
> 在一个方法的一对小括号中可以声明形参列表,形参的个数可以为0个、1个或多个。
> 如果有形参的话,格式为: (数据类型1 形参名1,数据类型2 形参名2,...)
开发中,设计一个方法时,是否需要提供形参呢?
> 根据题目的要求设计。
> 具体问题具体分析:调用此方法时,是否存在不确定性的数据。如果有,则以形参的方法传入此不确定的数据。
4.5 方法体:即为调用方法时,执行的代码。可以使用当前方法声明的形参,使用类中的成员变量。
5. 注意点
> Java里的方法`不能独立存在`,所有的方法必须定义在类里。
> 方法内可以使用类中的成员变量
> 方法内不可以定义方法,但是方法内可以调用本类中的其它方法。 ---> 递归方法中谈方法内自己调用自己。
> 类中不可以定义多个相同的方法。---> 方法的重载
4.2 return关键字
1. return的作用
> 作用1:结束当前方法的执行
> 作用2:"return + 变量/常量"结构在方法结束的同时,还可以返回一个数据。
2. 使用注意点:
与break、continue类似,其后不能声明执行语句。
5. 内存的分配使用
5.1 方法调用的内存解析
- 形参:方法声明时,一对小括号内声明的参数,简称:形参
- 实参:方法调用时,实际赋值给形参的值,称为:实参
过程概述:
每当调用一个方法时,方法就以栈帧的方法加载进虚拟机栈中。方法中声明的局部变量存放在栈帧中。
当方法执行结束时,栈帧就会弹出栈。栈帧中存放的局部变量也随之消亡。
5.2 目前为止,内存分析(重要)
- 基本原则
1、JVM中内存划分
- 栈:以栈帧为基本单位(每个方法对应一个栈帧);栈帧里存放局部变量。
- 堆:new 出来的"东西":数组实体(含数组元素)、对象实体(含成员变量)
2、区分清成员变量(类内部、方法外声明的)、局部变量(方法的形参、方法内定义的变量、构造器内定义的变量、构造器的形参、代码块内部等)
3、值传递机制:
- 如果参数是基本数据类型,传递的是基本数据类型变量存储的
数据值
- 如果参数是引用数据类型,传递的是引用数据类型变量存储的
地址值
6. 再谈方法
6.1 方法的重载(overload )
1. 定义:
在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。满足这样特点的多个方法彼此之间称为
方法的重载。
2. 总结为:"两同一不同":同一个类、相同的方法名;形参列表不同(参数的个数不同,参数的类型不同)
> 重载与否与形参名没有关系、返回值类型没有关系、权限修饰符没有关系
3. 举例
> Arrays中的重载的binarySearch(xxx) \\ equals(xxx,xxx) \\ toString(xxx)
> System.out的多个重载的println();
4. 如何判断两个方法是相同的呢?(换句话说,编译器是如何确定调用的某个具体的方法呢?)
> 在同一个类中,只要两个方法的方法名相同,且参数列表相同(参数的个数相同且参数类型相同),
则认为这两个方法是相同的。
> 与方法的权限修饰符、返回值类型、形参名都没有关系。
> 在同一个类,不能编写两个相同的方法的。
后续会讲:方法的重写(overwrite / override)
面试题:方法的重载与重写的区别?
throw \\ throws
Collection \\ Collections
final \\ finally \\ finalize
String \\ StringBuffer \\ StringBuilder
ArrayList \\ LinkedList
。。。
== 、equals()
抽象类、接口
6.2 可变个数形参的方法
1. 使用场景
JDK5.0的新特性。
如果方法在调用时,参数的类型是确定的,但是参数的个数不确定,则可以考虑使用可变个数形参的方法。
2. 格式:类型 ... 变量名
3. 说明:
> 可变个数形参的方法在调用时,可以传入0个,1个或多个参数。
> 可变个数形参的方法与参数是其它类型的同名方法构成重载。
> 可变个数形参的方法与参数是同样类型的数组参数构成的方法,在方法名相同的情况下,不构成重载。即两个方法不能
同时存在。
> 可变个数的形参在编译器看来就是同一个类型的数组参数
> 规定:可变个数的形参需要声明在方法形参列表的最后
> 一个方法的形参位置,最多只能有一个可变个数的形参
/*
String sql1 = "update customers set name = ?,salary = ? where id = ?";
String sql2 = "delete from customs where id = ?";
public void update(String sql,Object ... objs)
//使用可变形参objs中的各个元素值给形参sql中的?赋值
*/
6.3方法的参数传递机制(难点、重点)
1. 对于方法内声明的局部变量来说:
> 如果此局部变量是基本数据类型的,则将基本数据类型变量保存的数据值传递出去
> 如果此局部变量是引用数据类型的,则将引用数据类型变量保存的地址值传递出去
2. 方法的参数的传递机制:值传递
2.1 概念(复习)
形参:方法声明时,一对小括号内声明的参数,简称:形参
实参:方法调用时,实际赋值给形参的值,称为:实参
2.2 规则
> 如果此形参是基本数据类型的,则将基本数据类型的实参保存的数据值传递给形参
> 如果此形参是引用数据类型的,则将引用数据类型的实参保存的地址值传递给形参
3. 面试题:Java中的参数传递机制是什么? 值传递机制。
6.4 递归方法(熟悉)
1. 何为递归方法?
方法自己调用自己的现象就称为递归。
2. 递归方法分类
直接递归、间接递归。
3. 使用说明:
- 递归方法包含了一种`隐式的循环`。
- 递归方法会`重复执行`某段代码,但这种重复执行无须循环控制。
- 递归一定要向`已知方向`递归,否则这种递归就变成了无穷递归,停不下来,类似于`死循环`。最终发生`栈内存溢出`。
7. 对象数组(难点)
1. 何为对象数组?如何理解?
数组中的元素,如果存储的是对象的话,则称此数组为对象数组。
2. 举例:
String[] arr = new String[10];
arr[0] = "hello";
arr[1] = new String("abc");
Person[] arr1 = new Person[10];
arr1[0] = new Person();
Phone[] arr2 = new Phone[10];
3. 内存解析:
数组名(比如:stus)存储在栈空间
创建的20个学生对象,存储在堆空间中。学生对象的地址值存储在数组的每个元素中。
8. 关键字:package、import
- package:包,指明了Java中的类、接口等结构所在的包。声明在文件的首行
- import:导入。指明在当前类中使用的其它包中的结构。声明在package下,类的声明之前。
一、package关键字的使用
1. 说明
- package,称为包,用于指明该文件中定义的类、接口等结构所在的包。
- 一个源文件只能有一个声明包的package语句
- package语句作为Java源文件的第一条语句出现。若缺省该语句,则指定为无名包。以后声明源文件时,不要使用无名包。
- 包名,属于标识符,满足标识符命名的规则和规范(全部小写)、见名知意
- 包名推荐使用所在公司域名的倒置:com.atguigu.xxx。
- 大家取包名时不要使用"`java.xx`"包,否则运行会报错
- 包对应于文件系统的目录,package语句中用 “.” 来指明包(目录)的层次,每.一次就表示一层文件目录。
- 同一个包下可以声明多个结构(类、接口),但是不能定义同名的结构(类、接口)。不同的包下可以定义同名的结构(类、接口)
2. 包的作用
- 包可以包含类和子包,划分`项目层次`,便于管理
- 帮助`管理大型软件`系统:将功能相近的类划分到同一个包中。比如:MVC的设计模式
- 解决`类命名冲突`的问题 ---> 不同包下可以命名同名的类。
- 控制`访问权限` ---> 讲了封装性,大家就清楚了。
二、import关键字的使用
- import:导入,后面跟一个具体包下的类或接口等结构。
-为了使用定义在其它包中的Java类,需用import语句来显式引入指定包下所需要的类。
相当于`import语句告诉编译器到哪里去寻找这个类`。
- import语句,声明在包的声明和类的声明之间。
- 如果需要导入多个类或接口,那么就并列显式多个import语句即可
- 如果使用`a.*`导入结构,表示可以导入a包下的所有的结构。
举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。
- 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
- 如果已经导入java.a包下的类,那么如果需要使用a包的子包下的类的话,仍然需要导入。
- 如果在代码中使用不同包下的同名的类,那么就需要使用类的全类名的方式指明调用的是哪个类。
- (了解)`import static`组合的使用:调用指定类或接口下的静态的属性或方法
9. 面向对象的特征一:封装性
- 什么是封装性?
在Java实现项目时,将不用功能的代码封装进不同的方法。使用Java给我们提供的4种权限修饰对类及类的内部成员进行修饰。
体现被修饰的结构在调用时的可见性的大小。
- 如何体现封装性?
> 举例1:类中的属性私有化,提供公共的get()和set()方法,用于获取或设置此属性的值。
> 举例2:如果类中存在一些方法,这些方法只在类的内部使用,不希望对外暴露,则可以将这些方法声明为私有的。
> 举例3:单例设计模式。(后面讲static的时候说)
- 为什么需要封装性?
- `高内聚`:类的内部数据操作细节自己完成,不允许外部干涉;
- `低耦合`:仅暴露少量的方法给外部使用,尽量方便外部调用。
- 通俗的讲,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
10. 类的成员之三:构造器
1. 构造器的理解
体会1: Scanner scan = new Scanner(System.in);
Person per = new Person();
体会2:
construct : v. 建设、建造
construction: n. 建设、建造 CCB 中国建设银行 ICBC
constructor : n.建设者,建造者
2. 构造器的作用
>作用1:搭配new关键一起,用于对象的创建
>作用2:用于初始化对象中的成员变量
3. 构造器的使用说明
> 一个类中,如果没有显式提供构造器的话,则JVM会默认提供一个空参的构造器。(其权限修饰符与类的权限修饰符相同)
> 声明格式:权限修饰符 类名(形参列表)
> 一个类的多个构造器,彼此构成重载
> 如果一个类中,一旦显式的声明了构造器,则JVM不再提供默认的空参的构造器了。
> 结论:凡是类,都有构造器(自始至终都是对的)
11. 其它几个小知识
11.1 类中实例变量的赋值位置及顺序
0.实例变量:属于属性(或成员变量),不使用static修饰即可。
1. 在类的属性中,可以有哪些位置给属性赋值?
> ① 默认初始化 ---> 只执行一次
> ② 显式初始化 ---> 只执行一次
> ③ 构造器中初始化 ---> 只执行一次
*********************************
> ④ 创建对象以后,通过"对象.属性" 或"对象.方法"的方式,给属性赋值 ---> 可以多次执行
2. 这些位置执行的先后顺序是怎样?
① - ② - ③ - ④
3. 以上操作在对象创建过程中可以执行的次数如何?
①、②、③:只执行一次
④:可以多次执行
11.2 JavaBean
所谓JavaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法
11.3 UML类图
理解
11.4 匿名对象
//匿名对象
System.out.println(new Circle(2.5).findArea());
//知识点1:如上写法的匿名对象,只能被调用一次。
System.out.println(new Circle(2.5).getRadius());
//知识点2:开发中,常常将匿名对象作为参数传递给方法的形参。
Test4_5 test = new Test4_5();
test.show(new Circle(3.4));
第07章:面向对象-进阶
1. 关键字:this
- this可以调用属性、方法;构造器。
- 记住:this必须使用的场景:属性与形参同名时;调用重载的构造器
2. 面向对象特征二:继承性
-
为什么需要继承性?
- 继承的出现减少了代码冗余,提高了代码的复用性。
- 继承的出现,更有利于功能的扩展。
- 继承的出现让类与类之间产生了
is-a
的关系,为多态的使用提供了前提。
-
什么是继承性?
-
class B extends A
继承中的基本概念:
A类:父类、SuperClass、超类、基类
B类:子类、SubClass、派生类
-
-
继承性的基本使用
1. 有了继承性以后:
> 子类继承父类以后,就获取了父类中声明的所有的属性和方法。 ----> 刻画是否存在此属性、方法
但是,由于封装性的影响,可能导致子类不能调用。 ----> 刻画能否调用此属性、方法
> extends: 继承。还可以理解为“扩展、延展”。意味着子类在继承父类的基础上,还可以扩展自己特有的属性、方法。
父类、子类的关系不同于集合、子集的关系。
2. 默认的父类:
如果一个类显式声明了父类,则其父类为指定声明的父类。
如果一个类没有显式声明其父类,则默认继承于java.lang.Object类。
3. 补充说明:
> 一个父类可以被多个子类继承。
> 一个子类只能声明一个父类。----> Java中类的单继承性。
> Java中的类支持多层继承。
> 子类、父类是相对的概念。
> 概念:直接父类、间接父类
> Java中的任何类(除了java.lang.Object类)都直接或间接的继承于java.lang.Object类。
3. 方法的重写
1. 为什么需要方法的重写?
子类继承父类以后,父类中的方法在权限允许的情况下,子类可以直接调用。但是我们在一些场景中发现,父类
中的方法不适用于子类。怎么处理呢?需要使用方法的重写。
举例(银行账户):
class Account //账户
double balance; //余额
//取钱
public void withdraw(double amt)
if(balance >= amt)
balance -= amt;
System.out.println("取款成功");
//...
class CheckAccount extends Account //信用卡账户
double protectedBy; //可透支额度
//取钱
public void withdraw(double amt)
if(balance >= amt)
balance -= amt;
System.out.println("取款成功");
else if(protectedBy >= amt - balance)
protectedBy -= amt - balance;
balance = 0;
System.out.println("取款成功");
else
System.out.println("取款失败");
2. 何为方法的重写?
子类继承父类以后,对父类中继承过来的方法进行覆盖、覆写的操作。此操作就称为方法的重写。
3. 方法重写应遵循的规则
[复习]方法声明的格式:权限修饰符 返回值类型 方法名(形参列表) 方法体
具体规则:称谓:父类被重写的方法;子类重写父类的方法
> 子类重写父类的方法 与 父类被重写的方法的方法名、形参列表相同。
> 子类重写父类的方法的权限修饰符不小于父类被重写的方法的权限修饰符
> 返回值类型:
> 父类被重写的方法的返回值类型为void,则子类重写父类的方法的返回值类型必须为void
> 父类被重写的方法的返回值类型为基本数据类型,则子类重写父类的方法的返回值类型必须为同类型的基本数据类型
> 父类被重写的方法的返回值类型为引用数据类型,则子类重写父类的方法的返回值类型与父类的相同,或是父类的类型的子类。
技巧:建议子类重写父类的方法时,我们将权限修饰符、返回值类型都声明为与父类的方法相同的。
注意点:
> 子类不能重写父类中声明为private权限的方法。
4. 面试题:区分方法的重载(overload)与重写(override / overwrite)
重载:"两同一不同"
重写:子类在继承父类以后,可以对父类中的同名同参数的方法进行覆盖、覆写。此操作即为方法的重写。
具体的规则为:....。
4. 关键字:super
-
super调用父类的属性、方法;构造器
-
使用场景:子父类中出现同名属性;子类重写了父类的方法时。
super调用构造器,体现加载父类的结构。
-
5. 子类对象实例化的全过程(了解)
1. 从结果的角度来看:---->体现为类的继承性。
当子类继承父类以后,子类就获取了父类(直接父类、所有的间接父类)中声明的所有的属性、方法。
当我们创建了子类对象以后,在堆空间中就保存了子类本身及其所有的父类中声明的属性。同时,子类对象在权限允许
的情况下,可以调用子类及其所有的父类中声明的方法。
2. 从过程的角度来看:
当我们通过子类的构造器创建对象时,一定会直接或间接的调用到其直接父类的构造器,其直接父类的构造器同样会
直接或间接的调用到其父类的构造器,...,以此类推,最终一定会调用到java.lang.Object类的构造器为止。
因为我们调用过所有的父类的构造器,进而所有的父类就需要加载到内存中,进而堆空间中就有所有父类中声明的属性。
以及可以在权限允许的情况下,调用父类中声明的方法。
问题:在创建子类对象的过程中,一定会调用父类中的构造器吗? yes!
3. 问题:创建子类的对象时,内存中到底有几个对象?
只有1个!
6. 面向对象特征三:多态性
6.1 向上转型:多态
- Java中的多态性体现为:子类对象的多态性(狭义上理解)。即父类的引用指向子类的对象。
- 应用场景:当通过父类的引用调用方法时,实际执行的是子类重写父类的方法。
- 好处:多态性常使用在方法的形参位置。多态的出现,极大的减少了方法的重载,同时有利于程序的扩展。
- 举例:① equals(Object obj) ② Account - Customer : setAccount(Account acct) ③ 凡是代码中出现了抽象类、接口,都可以体现为多态性。
- 共识:Java中的多态性(广义上理解):1、子类对象的多态性。 2、方法的重写。
6.2 向下转型:多态的逆过程
- Student s = (Student)new Person(); //编译通过,运行不通过。
- 如何向下转型:使用强转符:()
- 可能出现的问题:可能会出现ClassCastException异常
- 如何解决?建议在强转前进行instanceof的判断
以上是关于Java基础复习笔记详细版的主要内容,如果未能解决你的问题,请参考以下文章