Java基础编程

一、1_java语言概述

整体内容概述

在这里插入图片描述

项目一:讲完流程控制时,可以做。第二章结束
项目二:讲完第四章面向对象(上),可以做
项目三:讲完第七章异常处理以后,可以做

附加项目一:讲完第七章异常处理以后,可以做
附加项目二:讲完第11章IO流以后,可以做

Java语言概述

1.基础常识
软件:即一系列按照特定顺序组织的计算机数据和指令的集合。分为:系统软件 和 应用软件
系统软件:windows , mac os , linux ,unix,android,ios,…
应用软件:word ,ppt,画图板,…
人机交互方式: 图形化界面 vs 命令行方式
应用程序 = 算法 + 数据结构
常用DOS命令:
在这里插入图片描述

2.计算机语言的发展迭代史
第一代:机器语言
第二代:汇编语言
第三代:高级语言

面向过程:C,Pascal、Fortran
面向对象:Java,JS,Python,Scala,…
3.Java语言版本迭代概述
1991年 Green项目,开发语言最初命名为Oak (橡树)
1994年,开发组意识到Oak 非常适合于互联网
1996年,发布JDK 1.0,约8.3万个网页应用Java技术来制作
1997年,发布JDK 1.1,JavaOne会议召开,创当时全球同类会议规模之最
1998年,发布JDK 1.2,同年发布企业平台J2EE
1999年,Java分成J2SE、J2EE和J2ME,JSP/Servlet技术诞生
2004年,发布里程碑式版本:JDK 1.5,为突出此版本的重要性,更名为JDK 5.0
2005年,J2SE -> JavaSE,J2EE -> JavaEE,J2ME -> JavaME
2009年,Oracle公司收购SUN,交易价格74亿美元
2011年,发布JDK 7.0
2014年,发布JDK 8.0,是继JDK 5.0以来变化最大的版本
2017年,发布JDK 9.0,最大限度实现模块化
2018年3月,发布JDK 10.0,版本号也称为18.3
2018年9月,发布JDK 11.0,版本号也称为18.9

4.Java语言应用的领域:

Java Web开发:后台开发
大数据开发:
Android应用程序开发:客户端开发
5.Java语言的特点
面向对象性:
两个要素:类、对象
三个特征:封装、继承、多态
健壮性:① 去除了C语言中的指针 ②自动的垃圾回收机制 -->仍然会出现内存溢出、内存泄漏
跨平台型:write once,run anywhere:一次编译,到处运行
功劳归功于:JVM
在这里插入图片描述

开发环境搭建

1.开发环境的搭建(重点)
1.1 JDK、JRE、JVM的关系
在这里插入图片描述

1.2 JDK的下载、安装
下载:官网,github
安装:傻瓜式安装:JDK 、JRE
注意问题:安装软件的路径中不能包含中文、空格。

1.3 path环境变量的配置
1.3.1 为什么配置path环境变量?
path环境变量:windows操作系统执行命令时所要搜寻的路径
为什么要配置path:希望java的开发工具(javac.exe,java.exe)在任何的文件路径下都可以执行成功。
1.3.2 如何配置?
在这里插入图片描述

第一个Java程序

1.开发体验——HelloWorld
在这里插入图片描述

1.1 编写
创建一个java源文件:HelloWorld.java
class HelloChina{
public static void main(String[] args){
System.out.println(“Hello,World!”);
}
}

1.2 编译:
javac HelloWorld.java
1.3 运行:
java HelloChina

2.常见问题的解决
在这里插入图片描述在这里插入图片描述

3.总结第一个程序

  1. java程序编写-编译-运行的过程
    编写:我们将编写的java代码保存在以".java"结尾的源文件中
    编译:使用javac.exe命令编译我们的java源文件。格式:javac 源文件名.java
    运行:使用java.exe命令解释运行我们的字节码文件。 格式:java 类名

在一个java源文件中可以声明多个class。但是,只能最多有一个类声明为public的。
而且要求声明为public的类的类名必须与源文件名相同。
3. 程序的入口是main()方法。格式是固定的。
4. 输出语句:
System.out.println():先输出数据,然后换行
System.out.print():只输出数据
5.每一行执行语句都以";"结束。
6.编译的过程:编译以后,会生成一个或多个字节码文件。字节码文件的文件名与java源文件中的类名相同。

注释与API文档等

1.注释:Comment
分类:
单行注释://
多行注释:/* /
文档注释:/
* */
作用:
① 对所写的程序进行解释说明,增强可读性。方便自己,方便别人
② 调试所写的代码
特点:
①单行注释和多行注释,注释了的内容不参与编译。
换句话说,编译以后生成的.class结尾的字节码文件中不包含注释掉的信息
② 注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档。
③ 多行注释不可以嵌套使用
2.Java API 文档: 
API:application programming interface。习惯上:将语言提供的类库,都称为api.
API文档:针对于提供的类库如何使用,给的一个说明书。类似于《新华字典》
3.良好的编程风格在这里插入图片描述

EditPlus的使用

1.开发工具说明:
在这里插入图片描述
在这里插入图片描述

2.EditPlus的使用:

在这里插入图片描述在这里插入图片描述

二、2_基本语法

1.关键字与标识符

在这里插入图片描述

1.java关键字的使用
定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词)
特点:关键字中所字母都为小写
具体哪些关键字:
在这里插入图片描述
在这里插入图片描述

2.保留字:现Java版本尚未使用,但以后版本可能会作为关键字使用。
具体哪些保留字:goto 、const
注意:自己命名标识符时要避免使用这些保留字

3.标识符的使用
定义:凡是自己可以起名字的地方都叫标识符。
涉及到的结构:
包名、类名、接口名、变量名、方法名、常量名
规则:(必须要遵守。否则,编译不通过)
在这里插入图片描述

规范:(可以不遵守,不影响编译和运行。但是要求大家遵守)
在这里插入图片描述

注意点:
在起名字时,为了提高阅读性,要尽量意义,“见名知意”。

代码简洁之道

第2章 有意义的命名
2.1 介绍
软件中随处可见命名。我们给变量、函数、参数、类和包命名。我们给源代码及源代码所在目录命名。
这么多命名要做,不妨做好它。下文列出了取个好名字的几条简单规则。

2.2 名副其实,见名知意
变量名太随意,haha、list1、ok、theList 这些都没啥意义

2.3 避免误导
包含List、import、java等类名、关键字或特殊字;
字母o与数字0,字母l与数字1等
提防使用不同之处较小的名称。比如:XYZControllerForEfficientHandlingOfStrings与XYZControllerForEfficientStorageOfStrings

2.4 做有意义的区分
反面教材,变量名:a1、a2、a3
避免冗余,不要出现Variable、表字段中避免出现table、字符串避免出现nameString,直接name就行,知道是字符串类型
再比如:定义了两个类:Customer类和CustomerObject类,如何区分?
定义了三个方法:getActiveAccount()、getActiveAccounts()、getActiveAccountInfo(),如何区分?

2.5 使用读得出来的名称
不要使用自己拼凑出来的单词,比如:xsxm(学生姓名);genymdhms(生成日期,年、月、日、时、分、秒)
所谓的驼峰命名法,尽量使用完整的单词

2.6 使用可搜索的名称
一些常量,最好不直接使用数字,而指定一个变量名,这个变量名可以便于搜索到.
比如:找MAX_CLASSES_PER_STUDENT很容易,但想找数字7就麻烦了。

2.7 避免使用编码
2.7.1 匈牙利语标记法
即变量名表明该变量数据类型的小写字母开始。例如,szCmdLine的前缀sz表示“以零结束的字符串”。
2.7.2 成员前缀
避免使用前缀,但是Android中一个比较好的喜欢用m表示私有等,个人感觉比较好
2.7.3 接口和实现
作者不喜欢把接口使用I来开头,实现也希望只是在后面添加Imp

2.8 避免思维映射
比如传统上惯用单字母名称做循环计数器。所以就不要给一些非计数器的变量命名为:i、j、k等

2.9 类名
类名与对象名应该是名词与名词短语。如Customer、WikiPage、Account和AddressParser。避免使用Data或Info这样的类名。
不能使动词。比如:Manage、Process

2.10 方法名
方法名应当是动词或者动词短语。如postPayment、deletePage或save

2.11 别扮可爱
有的变量名叫haha、banana
别用eatMyShorts()表示abort()

2.12 每个概念对应一个词
项目中同时出现controllers与managers,为什么不统一使用其中一种?
对于那些会用到你代码的程序员,一以贯之的命名法简直就是天降福音。

2.13 别用双关语
有时可能使用add并不合适,比例insert、append。add表示完整的新添加的含义。

2.14 使用解决方案领域名称
看代码的都是程序员,所以尽量用那些计算机科学术语、算法名、模式名、数学术语,
依据问题所涉领域来命名不算是聪明的做法。

2.15 使用源自所涉问题领域的名称
如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域而来的名称吧。
至少,负责维护代码的程序员就能去请教领域专家了。

2.16 添加有意义的语境
可以把相关的变量放到一个类中,使用这个类来表明语境。

2.17 不要添加没用的语境
名字中带有项目的缩写,这样完全没有必要。比如有一个名为“加油站豪华版”(Gas Station Deluxe)的项目,
在其中给每个类添加GSD前缀就不是什么好策略。

2.18 最后的话
取好名字最难的地方在于需要良好的描述技巧和共有文化背景。

变量的使用(重点)

1.变量的分类
1.1 按数据类型分类
在这里插入图片描述

详细说明:
//1. 整型:byte(1字节=8bit) \ short(2字节) \ int(4字节) \ long(8字节)
//① byte范围:-128 ~ 127
// ② 声明long型变量,必须以"l"或"L"结尾
// ③ 通常,定义整型变量时,使用int型。
//④整型的常量,默认类型是:int型
//2. 浮点型:float(4字节) \ double(8字节)
//① 浮点型,表示带小数点的数值
//② float表示数值的范围比long还大
//③ 定义float类型变量时,变量要以"f"或"F"结尾
//④ 通常,定义浮点型变量时,使用double型。
//⑤ 浮点型的常量,默认类型为:double
//3. 字符型:char (1字符=2字节)
//① 定义char型变量,通常使用一对’’,内部只能写一个字符
//② 表示方式:1.声明一个字符 2.转义字符 3.直接使用 Unicode 值来表示字符型常量
//4.布尔型:boolean
//① 只能取两个值之一:true 、 false
//② 常常在条件判断、循环结构中使用
1.2 按声明的位置分类(了解)

在这里插入图片描述

2.定义变量的格式:
数据类型 变量名 = 变量值;

数据类型 变量名;
变量名 = 变量值;

3.变量使用的注意点:
① 变量必须先声明,后使用
② 变量都定义在其作用域内。在作用域内,它是有效的。换句话说,出了作用域,就失效了
③ 同一个作用域内,不可以声明两个同名的变量
4.基本数据类型变量间运算规则
4.1 涉及到的基本数据类型:除了boolean之外的其他7种
4.2 自动类型转换(只涉及7种基本数据类型)
结论:当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型。
byte 、char 、short --> int --> long --> float --> double
特别的:当byte、char、short三种类型的变量做运算时,结果为int型
说明:此时的容量大小指的是,表示数的范围的大和小。比如:float容量要大于long的容量

4.3 强制类型转换(只涉及7种基本数据类型):自动类型提升运算的逆运算。
1.需要使用强转符:()
2.注意点:强制类型转换,可能导致精度损失。
4.4 String与8种基本数据类型间的运算

  1. String属于引用数据类型,翻译为:字符串
  2. 声明String类型变量时,使用一对""
  3. String可以和8种基本数据类型变量做运算,且运算只能是连接运算:+
  4. 运算的结果仍然是String类型
    避免:
    String s = 123;//编译错误
    String s1 = “123”;
    int i = (int)s1;//编译错误

进制(了解)

1.编程中涉及的进制及表示方式:
在这里插入图片描述

2.二进制的使用说明:
2.1 计算机底层的存储方式:所有数字在计算机底层都以二进制形式存在。
2.2 二进制数据的存储方式:所有的数值,不管正负,底层都以补码的方式存储。
2.3 原码、反码、补码的说明:
正数:三码合一
负数:
在这里插入图片描述

3.进制间的转换:
3.1 图示:
在这里插入图片描述

3.2 图示二进制转换为十进制:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

3.3 图示十进制转换为二进制:
在这里插入图片描述

3.4 二进制与八进制、十六进制间的转换:

在这里插入图片描述在这里插入图片描述

运算符

1-算术运算符

1.算术运算符: + - + - * / % (前)++ (后)++ (前)-- (后)-- +
【典型代码】
//除号:/
int num1 = 12;
int num2 = 5;
int result1 = num1 / num2;
System.out.println(result1);//2
// %:取余运算
//结果的符号与被模数的符号相同
//开发中,经常使用%来判断能否被除尽的情况。
int m1 = 12;
int n1 = 5;
System.out.println("m1 % n1 = " + m1 % n1);

	int m2 = -12;
	int n2 = 5;
	System.out.println("m2 % n2 = " + m2 % n2);

	int m3 = 12;
	int n3 = -5;
	System.out.println("m3 % n3 = " + m3 % n3);

	int m4 = -12;
	int n4 = -5;
	System.out.println("m4 % n4 = " + m4 % n4);
	//(前)++ :先自增1,后运算
	//(后)++ :先运算,后自增1
	int a1 = 10;
	int b1 = ++a1;
	System.out.println("a1 = " + a1 + ",b1 = " + b1);
	
	int a2 = 10;
	int b2 = a2++;
	System.out.println("a2 = " + a2 + ",b2 = " + b2);
	
	int a3 = 10;
	++a3;//a3++;
	int b3 = a3;
	//(前)-- :先自减1,后运算
	//(后)-- :先运算,后自减1
	
	int a4 = 10;
	int b4 = a4--;//int b4 = --a4;
	System.out.println("a4 = " + a4 + ",b4 = " + b4);

【特别说明的】
1.//(前)++ :先自增1,后运算
//(后)++ :先运算,后自增1
2.//(前)-- :先自减1,后运算
//(后)-- :先运算,后自减1
3.连接符:+:只能使用在String与其他数据类型变量之间使用。

2-赋值运算符

2.赋值运算符:= += -= = /= %=
【典型代码】
int i2,j2;
//连续赋值
i2 = j2 = 10;
//
**************
int i3 = 10,j3 = 20;
int num1 = 10;
num1 += 2;//num1 = num1 + 2;
System.out.println(num1);//12

	int num2 = 12;
	num2 %= 5;//num2 = num2 % 5;
	System.out.println(num2);

	short s1 = 10;
	//s1 = s1 + 2;//编译失败
	s1 += 2;//结论:不会改变变量本身的数据类型
	System.out.println(s1);

【特别说明的】
1.运算的结果不会改变变量本身的数据类型
2.
//开发中,如果希望变量实现+2的操作,有几种方法?(前提:int num = 10;)
//方式一:num = num + 2;
//方式二:num += 2; (推荐)

	//开发中,如果希望变量实现+1的操作,有几种方法?(前提:int num = 10;)
	//方式一:num = num + 1;
	//方式二:num += 1; 
	//方式三:num++; (推荐)

3-比较运算符

3.比较运算符(关系运算符): == != > < >= <= instanceof
【典型代码】
int i = 10;
int j = 20;

	System.out.println(i == j);//false
	System.out.println(i = j);//20

	boolean b1 = true;
	boolean b2 = false;
	System.out.println(b2 == b1);//false
	System.out.println(b2 = b1);//true

【特别说明的】
1.比较运算符的结果是boolean类型
2.> < >= <= :只能使用在数值类型的数据之间。
3. == 和 !=: 不仅可以使用在数值类型数据之间,还可以使用在其他引用类型变量之间。
Account acct1 = new Account(1000);
Account acct2 = new Account(1000);
boolean b1 = (acct1 == acct2);//比较两个Account是否是同一个账户。
boolean b2 = (acct1 != acct2);//

4-逻辑运算符

4.逻辑运算符:& && | || ! ^
【典型代码】
//区分& 与 &&
//相同点1:& 与 && 的运算结果相同
//相同点2:当符号左边是true时,二者都会执行符号右边的运算
//不同点:当符号左边是false时,&继续执行符号右边的运算。&&不再执行符号右边的运算。
//开发中,推荐使用&&
boolean b1 = true;
b1 = false;
int num1 = 10;
if(b1 & (num1++ > 0)){
System.out.println(“我现在在北京”);
}else{
System.out.println(“我现在在南京”);
}

	System.out.println("num1 = " + num1);
	

	boolean b2 = true;
	b2 = false;
	int num2 = 10;
	if(b2 && (num2++ > 0)){
		System.out.println("我现在在北京");
	}else{
		System.out.println("我现在在南京");
	}

	System.out.println("num2 = " + num2);

	// 区分:| 与 || 
	//相同点1:| 与  || 的运算结果相同
	//相同点2:当符号左边是false时,二者都会执行符号右边的运算
	//不同点3:当符号左边是true时,|继续执行符号右边的运算,而||不再执行符号右边的运算
	//开发中,推荐使用||
	boolean b3 = false;
	b3 = true;
	int num3 = 10;
	if(b3 | (num3++ > 0)){
		System.out.println("我现在在北京");
	}else{
		System.out.println("我现在在南京");
	}
	System.out.println("num3 = " + num3);


	boolean b4 = false;
	b4 = true;
	int num4 = 10;
	if(b4 || (num4++ > 0)){
		System.out.println("我现在在北京");
	}else{
		System.out.println("我现在在南京");
	}
	System.out.println("num4 = " + num4);

【特别说明的】
1.逻辑运算符操作的都是boolean类型的变量。而且结果也是boolean类型

5-位运算符

5.位运算符:<< >> >>> & | ^ ~
【典型代码】
int i = 21;
i = -21;
System.out.println(“i << 2 :” + (i << 2));
System.out.println(“i << 3 :” + (i << 3));
System.out.println(“i << 27 :” + (i << 27));

	int m = 12;
	int n = 5;
	System.out.println("m & n :" + (m & n));
	System.out.println("m | n :" + (m | n));
	System.out.println("m ^ n :" + (m ^ n));

【面试题】 你能否写出最高效的2 * 8的实现方式?
答案:2 << 3 或 8 << 1
【特别说明的】

  1. 位运算符操作的都是整型的数据
  2. << :在一定范围内,每向左移1位,相当于 * 2

    :在一定范围内,每向右移1位,相当于 / 2

典型题目:
1.交换两个变量的值。
2.实现60的二进制到十六进制的转换

6-三元运算符

6.三元运算符:(条件表达式)? 表达式1 : 表达式2
【典型代码】
1.获取两个整数的较大值
2.获取三个数的最大值
【特别说明的】

  1. 说明
    ① 条件表达式的结果为boolean类型
    ② 根据条件表达式真或假,决定执行表达式1,还是表达式2.
    如果表达式为true,则执行表达式1。
    如果表达式为false,则执行表达式2。
    ③ 表达式1 和表达式2要求是一致的。
    ④ 三元运算符可以嵌套使用

凡是可以使用三元运算符的地方,都可以改写为if-else
反之,不成立。
3. 如果程序既可以使用三元运算符,又可以使用if-else结构,那么优先选择三元运算符。原因:简洁、执行效率高。

流程控制

顺序结构:程序从上到下执行。

分支结构:
if-else if - else
switch-case

循环结构:
for
while
do-while

分支结构

1.if-else条件判断结构
1.1.
结构一:
if(条件表达式){
执行表达式
}

结构二:二选一
if(条件表达式){
执行表达式1
}else{
执行表达式2
}

结构三:n选一
if(条件表达式){
执行表达式1
}else if(条件表达式){
执行表达式2
}else if(条件表达式){
执行表达式3
}

else{
执行表达式n
}

1.2.说明:

  1. else 结构是可选的。
  2. 针对于条件表达式:

    如果多个条件表达式之间是“互斥”关系(或没有交集的关系),哪个判断和执行语句声明在上面还是下面,无所谓。
    如果多个条件表达式之间有交集的关系,需要根据实际情况,考虑清楚应该将哪个结构声明在上面。
    如果多个条件表达式之间有包含的关系,通常情况下,需要将范围小的声明在范围大的上面。否则,范围小的就没机会执行了。

  3. if-else结构是可以相互嵌套的。
  4. 如果if-else结构中的执行语句只有一行时,对应的一对{}可以省略的。但是,不建议大家省略。

2.switch-case选择结构
switch(表达式){
case 常量1:
执行语句1;
//break;
case 常量2:
执行语句2;
//break;

default:
执行语句n;
//break;
}
2.说明:
① 根据switch表达式中的值,依次匹配各个case中的常量。一旦匹配成功,则进入相应case结构中,调用其执行语句。
当调用完执行语句以后,则仍然继续向下执行其他case结构中的执行语句,直到遇到break关键字或此switch-case结构
末尾结束为止。
② break,可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出switch-case结构
③ switch结构中的表达式,只能是如下的6种数据类型之一:
byte 、short、char、int、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)
④ case 之后只能声明常量。不能声明范围。
⑤ break关键字是可选的。
⑥ default:相当于if-else结构中的else.
default结构是可选的,而且位置是灵活的。
3.如果switch-case结构中的多个case的执行语句相同,则可以考虑进行合并。
4.break在switch-case中是可选的

循环结构

1.循环结构的四要素
① 初始化条件
② 循环条件 —>是boolean类型
③ 循环体
④ 迭代条件
说明:通常情况下,循环结束都是因为②中循环条件返回false了。

2.三种循环结构:
2.1 for循环结构
for(①;②;④){

}
执行过程:① - ② - ③ - ④ - ② - ③ - ④ - … - ②
2.2 while循环结构

while(②){
③;
④;
}
执行过程:① - ② - ③ - ④ - ② - ③ - ④ - … - ②
说明:
写while循环千万小心不要丢了迭代条件。一旦丢了,就可能导致死循环!

for和while循环总结:

  1. 开发中,基本上我们都会从for、while中进行选择,实现循环结构。
  2. for循环和while循环是可以相互转换的!
    区别:for循环和while循环的初始化条件部分的作用范围不同。
  3. 我们写程序,要避免出现死循环。
    2.3 do-while循环结构

    do{
    ③;
    ④;
    }while(②);
    执行过程:① - ③ - ④ - ② - ③ - ④ - … - ②

说明:
1.do-while循环至少会执行一次循环体!
2.开发中,使用for和while更多一些。较少使用do-while

3.“无限循环”结构: while(true) 或 for(;😉
总结:如何结束一个循环结构?
方式一:当循环条件是false时
方式二:在循环体中,执行break

4.嵌套循环
1.嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环
内层循环:循环结构A
外层循环:循环结构B
2.说明:
① 内层循环结构遍历一遍,只相当于外层循环循环体执行了一次
② 假设外层循环需要执行m次,内层循环需要执行n次。此时内层循环的循环体一共执行了m * n次
③ 外层循环控制行数,内层循环控制列数
【典型练习】
//练习一:
/*
******
******
******
******
/
for(int j = 1;j <= 4;j++ ){
for(int i = 1;i <= 6;i++){
System.out.print(’
’);
}
System.out.println();
}
//练习二:
/* i(行号) j(*的个数)
* 1 1
** 2 2
*** 3 3
**** 4 4
***** 5 5
*/

	for(int i = 1;i <= 5;i++){//控制行数
		for(int j = 1;j <= i;j++){//控制列数
			System.out.print("*");
		
		}
		System.out.println();
	}
	//练习三:九九乘法表
	//练习四:100以内的质数

补充:衡量一个功能代码的优劣:
1.正确性
2.可读性
3.健壮性
4.高效率与低存储:时间复杂度 、空间复杂度 (衡量算法的好坏)

如何理解流程控制的练习:
流程控制结构的使用 + 算法逻辑

关键字:break和continue

break和continue关键字的使用
使用范围 循环中使用的作用(不同点) 相同点
break: switch-case
循环结构中 结束当前循环 关键字后面不能声明执行语句

continue: 循环结构中 结束当次循环 关键字后面不能声明执行语句

补充:带标签的break和continue的使用

return在方法中讲。

补充:Scanner类的使用

/*
如何从键盘获取不同类型的变量:需要使用Scanner类

具体实现步骤:
1.导包:import java.util.Scanner;
2.Scanner的实例化:Scanner scan = new Scanner(System.in);
3.调用Scanner类的相关方法(next() / nextXxx()),来获取指定类型的变量

注意:
需要根据相应的方法,来输入指定类型的值。如果输入的数据类型与要求的类型不匹配时,会报异常:InputMisMatchException
导致程序终止。
*/
//1.导包:import java.util.Scanner;
import java.util.Scanner;

class ScannerTest{

public static void main(String[] args){
	//2.Scanner的实例化
	Scanner scan = new Scanner(System.in);
	
	//3.调用Scanner类的相关方法
	System.out.println("请输入你的姓名:");
	String name = scan.next();
	System.out.println(name);

	System.out.println("请输入你的芳龄:");
	int age = scan.nextInt();
	System.out.println(age);

	System.out.println("请输入你的体重:");
	double weight = scan.nextDouble();
	System.out.println(weight);

	System.out.println("你是否相中我了呢?(true/false)");
	boolean isLove = scan.nextBoolean();
	System.out.println(isLove);

	//对于char型的获取,Scanner没有提供相关的方法。只能获取一个字符串
	System.out.println("请输入你的性别:(男/女)");
	String gender = scan.next();//"男"
	char genderChar = gender.charAt(0);//获取索引为0位置上的字符
	System.out.println(genderChar);	
}

}

3_数组

数组的概述

  • 1.数组的理解:数组(Array),是多个相同类型数据一定顺序排列的集合,并使用一个名字命名,
  • 并通过编号的方式对这些数据进行统一管理。
  • 2.数组相关的概念:
  • 数组名

  • 元素

  • 角标、下标、索引

  • 数组的长度:元素的个数

  • 3.数组的特点:
  • 1数组是序排列的
  • 2数组属于引用数据类型的变量。数组的元素,既可以是基本数据类型,也可以是引用数据类型
  • 3创建数组对象会在内存中开辟一整块连续的空间
  • 4数组的长度一旦确定,就不能修改。
    1. 数组的分类:
  • ① 照维数:一维数组、二维数组、。。。
  • ② 照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组

数据结构:
1.数据与数据之间的逻辑关系:集合、一对一、一对多、多对多
2.数据的存储结构:
线性表:顺序表(比如:数组)、链表、栈、队列
树形结构:二叉树
图形结构:

算法:
排序算法:
搜索算法:

一维数组

1.一维数组的声明与初始化
正确的方式:
int num;//声明
num = 10;//初始化
int id = 1001;//声明 + 初始化

	int[] ids;//声明
	//1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行
	ids = new int[]{1001,1002,1003,1004};

	//1.2动态初始化:数组的初始化和数组元素的赋值操作分开进行
	String[] names = new String[5];//初始化


int[] arr4 = {1,2,3,4,5};//类型推断

错误的方式:
// int[] arr1 = new int[];
// int[5] arr2 = new int[5];
// int[] arr3 = new int[3]{1,2,3};

2.一维数组元素的引用:通过角标的方式调用。
//数组的角标(或索引从0开始的,到数组的长度-1结束。
names[0] = “王铭”;
names[1] = “王赫”;
names[2] = “张学良”;
names[3] = “孙居龙”;
names[4] = “王宏志”;//charAt(0)

3.数组的属性:length
System.out.println(names.length);//5
System.out.println(ids.length);

说明:
数组一旦初始化,其长度就是确定的。arr.length
数组长度一旦确定,就不可修改。
4.一维数组的遍历
for(int i = 0;i < names.length;i++){
System.out.println(names[i]);
}
5.一维数组元素的默认初始化值+类中的属性也是
> 数组元素是整型:0

  •  > 数组元素是浮点型:0.0
    
  •  > 数组元素是char型:0或'\u0000',而非'0'
    
  •  > 数组元素是boolean型:false
    
  •  > 数组元素是引用数据类型:null
    

6.一维数组的内存解析
在这里插入图片描述

二维数组

1.如何理解二维数组?
数组属于引用数据类型
数组的元素也可以是引用数据类型
一个一维数组A的元素如果还是一个一维数组类型的,则,此数组A称为二维数组。

2.二维数组的声明与初始化
正确的方式:

int[] arr = new int[]{1,2,3};//一维数组
	//静态初始化
	int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
	//动态初始化1
	String[][] arr2 = new String[3][2];
	//动态初始化2
	String[][] arr3 = new String[3][];
//也是正确的写法:
	int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
	int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};//类型推断

错误的方式:
// String[][] arr4 = new String[][4];
// String[4][3] arr5 = new String[][];
// int[][] arr6 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};
3.如何调用二维数组元素:
System.out.println(arr1[0][1]);//2
System.out.println(arr2[1][1]);//null

	arr3[1] = new String[4];
	System.out.println(arr3[1][0]);
System.out.println(arr3[0]);//

4.二维数组的属性:
System.out.println(arr4.length);//3
System.out.println(arr4[0].length);//3
System.out.println(arr4[1].length);//4
5.遍历二维数组元素
for(int i = 0;i < arr4.length;i++){

		for(int j = 0;j < arr4[i].length;j++){
			System.out.print(arr4[i][j] + "  ");
		}
		System.out.println();
}

6.二维数组元素的默认初始化值

  • 规定:二维数组分为外层数组的元素,内层数组的元素
  •  int[][] arr = new int[4][3];
    
  •  外层元素:arr[0],arr[1]等
    
  •  内层元素:arr[0][0],arr[1][2]等
    
  • ⑤ 数组元素的默认初始化值
  • 针对于初始化方式一:比如:int[][] arr = new int[4][3];
  •  外层元素的初始化值为:地址值
    
  •  内层元素的初始化值为:与一维数组初始化情况相同
    
  • 针对于初始化方式二:比如:int[][] arr = new int[4][];
  •  外层元素的初始化值为:null
    
  •  内层元素的初始化值为:不能调用,否则报错。
    

7.二维数组的内存结构

在这里插入图片描述

数组的常见算法

1.数组的创建与元素赋值:
杨辉三角(二维数组)、回形数(二维数组)、6个数,1-30之间随机生成且不重复。
2.针对于数值型的数组:
最大值、最小值、总和、平均数等
3.数组的赋值与复制
int[] array1,array2;
array1 = new int[]{1,2,3,4};
3.1 赋值:
array2 = array1;
如何理解:将array1保存的数组的地址值赋给了array2,使得array1和array2共同指向堆空间中的同一个数组实体。

3.2 复制:
array2 = new int[array1.length];
for(int i = 0;i < array2.length;i++){
array2[i] = array1[i];
}
在这里插入图片描述

如何理解:我们通过new的方式,给array2在堆空间中新开辟了数组的空间。将array1数组中的元素值一个一个的赋值到array2数组中。
4.数组元素的反转
//方法一:
// for(int i = 0;i < arr.length / 2;i++){
// String temp = arr[i];
// arr[i] = arr[arr.length - i -1];
// arr[arr.length - i -1] = temp;
// }

	//方法二:

// for(int i = 0,j = arr.length - 1;i < j;i++,j–){
// String temp = arr[i];
// arr[i] = arr[j];
// arr[j] = temp;
// }

5.数组中指定元素的查找:搜索、检索
5.1 线性查找:
实现思路:通过遍历的方式,一个一个的数据进行比较、查找。
适用性:具有普遍适用性。
5.2 二分法查找:
实现思路:每次比较中间值,折半的方式检索。
适用性:(前提:数组必须有序)

6.数组的排序算法
在这里插入图片描述

理解:
1)衡量排序算法的优劣:
时间复杂度、空间复杂度、稳定性

2)排序的分类:内部排序 与 外部排序(需要借助于磁盘)

3)不同排序算法的时间复杂度
在这里插入图片描述

4)手写冒泡排序

int[] arr = new int[]{43,32,76,-98,0,64,33,-21,32,99};
	
	//冒泡排序
	for(int i = 0;i < arr.length - 1;i++){
		
		for(int j = 0;j < arr.length - 1 - i;j++){
			
			if(arr[j] > arr[j + 1]){
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
			
		}
		
	}		

Arrays工具类的使用

1.理解:
① 定义在java.util包下。
② Arrays:提供了很多操作数组的方法。

2.使用:

//1.boolean equals(int[] a,int[] b):判断两个数组对象是否相等。
	int[] arr1 = new int[]{1,2,3,4};
	int[] arr2 = new int[]{1,3,2,4};
	boolean isEquals = Arrays.equals(arr1, arr2);
	System.out.println(isEquals);
	
	//2.String toString(int[] a):输出数组信息。
	System.out.println(Arrays.toString(arr1));
	
		
	//3.void fill(int[] a,int val):将指定值填充到数组之中。
	Arrays.fill(arr1,10);
	System.out.println(Arrays.toString(arr1));
	

	//4.void sort(int[] a):对数组进行排序。
	Arrays.sort(arr2);
	System.out.println(Arrays.toString(arr2));
	
	//5.int binarySearch(int[] a,int key)
	int[] arr3 = new int[]{-98,-34,2,34,54,66,79,105,210,333};
	int index = Arrays.binarySearch(arr3, 210);
	if(index >= 0){
		System.out.println(index);
	}else{
		System.out.println("未找到");
	}

数组的常见异常

1.数组角标越界异常:ArrayIndexOutOfBoundsException

	int[] arr = new int[]{1,2,3,4,5};

// for(int i = 0;i <= arr.length;i++){
// System.out.println(arr[i]);
// }

// System.out.println(arr[-2]);

// System.out.println(“hello”);
2.空指针异常:NullPointerException
//情况一:
// int[] arr1 = new int[]{1,2,3};
// arr1 = null;
// System.out.println(arr1[0]);

	//情况二:

// int[][] arr2 = new int[4][];
// System.out.println(arr2[0][0]);

	//情况:
	String[] arr3 = new String[]{"AA","BB","CC"};
	arr3[0] = null;
	System.out.println(arr3[0].toString());

小知识:一旦程序出现异常,未处理时,就终止执行。

4_面向对象-上

类与对象

1.面向对象学习的三条主线:

  • 1.Java类及类的成员:属性、方法、构造器;代码块、内部类
  • 2.面向对象的大特征:封装性、继承性、多态性、(抽象性)
  • 3.其它关键字:this、super、static、final、abstract、interface、package、import等
  • “大处着眼,小处着手”

一个源文件只能有一个public类,但可以有多个类,多个类都可以由main方法(普通方法),但只能有一个作为入口。

2.面向对象与面向过程(理解)
1.面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
2.面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。

举例对比:人把大象装进冰箱。

3.完成一个项目(或功能)的思路:
在这里插入图片描述

4.面向对象中两个重要的概念:
类:对一类事物的描述,是抽象的、概念上的定义
对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)

面向对象程序设计的重点是类的设计
设计类,就是设计类的成员。

二者的关系:
对象,是由类new出来的,派生出来的。
5.面向对象思想落地实现的规则一

  • 1.创建类,设计类的成员
  • 2.创建类的对象
  • 3.通过“对象.属性”或“对象.方法”调用对象的结构

补充:几个概念的使用说明

  • 属性 = 成员变量 = field = 域、字段
  • 方法 = 成员方法 = 函数 = method
  • 创建类的对象 = 类的实例化 = 实例化类

6.对象的创建与对象的内存解析
典型代码:
Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;//没有新创建一个对象,共用一个堆空间中的对象实体。
说明:
如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。

内存解析:
在这里插入图片描述
在这里插入图片描述

7.匿名对象:我们创建的对象,没显式的赋给一个变量名。即为匿名对象
特点:匿名对象只能调用一次。
举例:
new Phone().sendEmail();
new Phone().playGame();

	new Phone().price = 1999;
	new Phone().showPrice();//0.0

应用场景:
PhoneMall mall = new PhoneMall();

//匿名对象的使用
mall.show(new Phone());
其中,
class PhoneMall{
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}

}
8.理解"万事万物皆对象"
1.在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构

  •  >Scanner,String等
    
  •  >文件:File
    
  •  >网络资源:URL
    

2.涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。

JVM内存结构

编译完源程序以后,生成一个或多个字节码文件。
我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。
在这里插入图片描述

《JVM规范》

虚拟机栈,即为平时提到的栈结构。我们将局部变量存储在栈结构中
堆,我们将new出来的结构(比如:数组、对象)加载在对空间中。补充:对象的属性(非static的)加载在堆空间中。
方法区:类的加载信息、常量池、静态域

类的结构之一:属性

类的设计中,两个重要结构之一:属性

对比:属性 vs 局部变量

1.相同点:

  •  1.1  定义变量的格式:数据类型  变量名 = 变量值
    
  •  1.2 先声明,后使用
    
  •  1.3 变量都其对应的作用域 
    

2.不同点:
2.1 在类中声明的位置的不同

  •  属性:直接定义在类的一对{}内
    
  •  局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
    
  •  2.2 关于权限修饰符的不同
    
  •  属性:可以在声明属性时,指明其权限,使用权限修饰符。
    
  •  	常用的权限修饰符:private、public、缺省、protected  --->封装性
    
  •  	目前,大家声明属性时,都使用缺省就可以了。
    
  •  局部变量:不可以使用权限修饰符。
    
  •  2.3 默认初始化值的情况:
    
  •  属性:类的属性,根据其类型,都默认初始化值。
    
  •  	整型(byte、short、int、long:0)
    
  •  	浮点型(float、double:0.0)
    
  •  	字符型(char:0  (或'\u0000'))
    
  •  	布尔型(boolean:false)
    
  •  	引用数据类型(类、数组、接口:null)
    
  •  局部变量:没默认初始化值。
    
  •  	意味着,我们在调用局部变量之前,一定要显式赋值。
    
  •  	特别地:形参在调用时,我们赋值即可。
    
  •  2.4 在内存中加载的位置:
    
  •  属性:加载到堆空间中   (非static)
    
  •  局部变量:加载到栈空间
    

补充:回顾变量的分类:
方式一:按照数据类型:
在这里插入图片描述

方式二:按照在类中声明的位置:
在这里插入图片描述

类的结构之二:方法

类的设计中,两个重要结构之二:方法
方法:描述类应该具的功能。

  • 比如:Math类:sqrt()\random() …
  • Scanner类:nextXxx() ...
    
  • Arrays类:sort() \ binarySearch() \ toString() \ equals() \ ...
    
  • 1.举例:
  • public void eat(){}
  • public void sleep(int hour){}
  • public String getName(){}
  • public String getNation(String nation){}
    1. 方法的声明:权限修饰符 返回值类型 方法名(形参列表){
  •  			方法体
    
  •  	  }
    
  • 注意:static、final、abstract 来修饰的方法,后面再讲。
    1. 说明:
  •  3.1 关于权限修饰符:默认方法的权限修饰符先都使用public
    
  •  	Java规定的4种权限修饰符:private、public、缺省、protected  -->封装性再细说
    
  •  3.2 返回值类型: 返回值  vs 没返回值
    
  •  	3.2.1  如果方法返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用
    
  •            return关键字来返回指定类型的变量或常量:“return 数据”。
    
  •  		  如果方法没返回值,则方法声明时,使用void来表示。通常,没返回值的方法中,就不需要
    
  •           使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。
    
  •  	3.2.2 我们定义方法该不该返回值?
    
  •  		① 题目要求
    
  •  		② 凭经验:具体问题具体分析
    
  •  3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
    
  •  3.4 形参列表: 方法可以声明0个,1个,或多个形参。
    
  •     3.4.1 格式:数据类型1 形参1,数据类型2 形参2,...
    
  •     3.4.2 我们定义方法时,该不该定义形参?
    
  •     		① 题目要求
    
  •     		② 凭经验:具体问题具体分析
    
  •  3.5 方法体:方法功能的体现。 	
    
  1. 方法的使用中,可以调用当前类的属性或方法
  •  	特殊的:方法A中又调用了方法A:递归方法。
    
  • 方法中,不可以定义方法。
    

关键字:return

return关键字:
1.使用范围:使用在方法体中
2.作用:① 结束方法

  •  ② 针对于返回值类型的方法,使用"return 数据"方法返回所要的数据。
    

3.注意点:return关键字后面不可以声明执行语句。

方法的重载

1.方法的重载的概念
定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
*
总结:“两同一不同”:同一个类、相同方法名(返回值可以不同)
参数列表不同:参数个数不同,参数类型不同

构成重载的举例:
举例一:Arrays类中重载的sort() / binarySearch();PrintStream中的println()
举例二:
//如下的4个方法构成了重载
public void getSum(int i,int j){
System.out.println(“1”);
}

public void getSum(double d1,double d2){
	System.out.println("2");
}

public void getSum(String s ,int i){
	System.out.println("3");
}

public void getSum(int i,String s){
	System.out.println("4");
}

不构成重载的举例:
//如下的3个方法不能与上述4个方法构成重载
// public int getSum(int i,int j){
// return 0;
// }

// public void getSum(int m,int n){
//
// }

// private void getSum(int i,int j){
//
// }
3. 如何判断是否构成方法的重载?
严格按照定义判断:两同一不同。
跟方法的权限修饰符、返回值类型、形参变量名、方法体都没关系!
4.如何确定类中某一个方法的调用:
方法名 —> 参数列表

面试题:方法的重载与重写的区别?

throws\throw
String\StringBuffer\StringBuilder
Collection\Collections
final\finally\finalize

抽象类、接口
sleep() / wait()

可变个数形参的方法

1.使用说明:

  • 1.jdk 5.0新增的内容
  • 2.具体使用:
  • 2.1 可变个数形参的格式:数据类型 … 变量名
  • 2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
  • 2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
  • 2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
  • 2.5 可变个数形参在方法的形参中,必须声明在末尾
  • 2.6 可变个数形参在方法的形参中,最多只能声明一个可变形参。
  • 2.7 String… args args.length=可变性惨中的参数个数
    2.举例说明:
    public void show(int i){
}

public void show(String s){
	System.out.println("show(String)");
}

public void show(String ... strs){
	System.out.println("show(String ... strs)");
	
	for(int i = 0;i < strs.length;i++){
		System.out.println(strs[i]);
	}
}
//不能与上一个方法同时存在

// public void show(String[] strs){
//
// }
调用时:
test.show(“hello”);
test.show(“hello”,“world”);
test.show();

	test.show(new String[]{"AA","BB","CC"});

java的值传递机制

1.针对于方法内变量的赋值举例:
System.out.println("***********基本数据类型:****************");
int m = 10;
int n = m;

	System.out.println("m = " + m + ", n = " + n);
	
	n = 20;
	
	System.out.println("m = " + m + ", n = " + n);
	
	System.out.println("***********引用数据类型:****************");
	
	Order o1 = new Order();
	o1.orderId = 1001;
	
	Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。
	
	System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
	
	o2.orderId = 1002;
	
	System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);

规则:
如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。

2.针对于方法的参数概念
形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据

3.java中参数传递机制:值传递
规则:

  • 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
  • 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。

推广:
如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。

4.典型例题与内存解析:
【例题1】
在这里插入图片描述

【例题2】

在这里插入图片描述

递归方法

1.定义:
递归方法:一个方法体内调用它自身。
2.如何理解递归方法?

方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
3.举例:
// 例1:计算1-n之间所自然数的和
public int getSum(int n) {// 3

	if (n == 1) {
		return 1;
	} else {
		return n + getSum(n - 1);
	}

}

// 例2:计算1-n之间所自然数的乘积:n!
public int getSum1(int n) {

	if (n == 1) {
		return 1;
	} else {
		return n * getSum1(n - 1);
	}

}

//例3:已知一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
//其中n是大于0的整数,求f(10)的值。
public int f(int n){
	if(n == 0){
		return 1;
	}else if(n == 1){
		return 4;
	}else{

// return f(n + 2) - 2 * f(n + 1);
return 2*f(n - 1) + f(n - 2);
}
}

//例4:斐波那契数列

//例5:汉诺塔问题

//例6:快排

面向对象的特征一:封装性

面向对象的特征一:封装与隐藏
1.为什么要引入封装性?
我们程序设计追求“高内聚,低耦合”。
高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
低耦合 :仅对外暴露少量的方法用于使用。

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。

2.问题引入:
当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs()同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private).
–>此时,针对于属性就体现了封装性。
3.封装性思想具体的代码体现:
体现一:将类的属性xxx私化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
private double radius;
public void setRadius(double radius){
this.radius = radius;
}
public double getRadius(){
return radius;
}
体现二:不对外暴露的私有的方法
体现三:单例模式(将构造器私有化)
体现四:如果不希望类在包外被调用,可以将类设置为缺省的。

4.Java规定的四种权限修饰符
4.1 权限从小到大顺序为:private < 缺省 < protected < public
4.2 具体的修饰范围:
在这里插入图片描述

4.3 权限修饰符可用来修饰的结构说明:
4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
修饰类的话,只能使用:缺省、public

类的结构之三:构造器

1.构造器(或构造方法):Constructor 不能被重写
构造器的作用:

  • 1.创建对象
  • 2.初始化对象的信息
    2.使用说明:
  • 1.如果没显式的定义类的构造器的话,则系统默认提供一个空参的构造器
  • 2.定义构造器的格式:权限修饰符 类名(形参列表){}
  • 3.一个类中定义的多个构造器,彼此构成重载
  • 4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
  • 5.一个类中,至少会有一个构造器。

3.举例:
//构造器
public Person(){
System.out.println(“Person()…”);
}

public Person(String n){
	name = n;
	
}

public Person(String n,int a){
	name = n;
	age = a;
}

属性赋值顺序

  • 总结:属性赋值的先后顺序
  • ① 默认初始化
  • ② 显式初始化
  • ③ 构造器中初始化

  • ④ 通过"对象.方法" 或 "对象.属性"的方式,赋值
  • 以上操作的先后顺序:① - ② - ③ - ④

JavaBean的概念

所谓JavaBean,是指符合如下标准的Java类:
	>类是公共的
	>一个无参的公共的构造器
	>属性,且对应的get、set方法

关键字:this

1.可以调用的结构:属性、方法;构造器
2.this调用属性、方法:
this理解为:当前对象 或 当前正在创建的对象

2.1 在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,

  • 通常情况下,我们都择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式
  • 的使用"this.变量"的方式,表明此变量是属性,而非形参。
  • 2.2 在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法。但是,通常情况下,我们都择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参。

3.this调用构造器:
① 我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
② 构造器中不能通过"this(形参列表)“方式调用自己
③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)”
④ 规定:"this(形参列表)“必须声明在当前构造器的首行
⑤ 构造器内部,最多只能声明一个"this(形参列表)”,用来调用其他的构造器

关键字:package/import

  1. package的使用
    1.1 使用说明:
  • 1.为了更好的实现项目中类的管理,提供包的概念
  • 2.使用package声明类或接口所属的包,声明在源文件的首行
  • 3.包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”
  • 4.每"."一次,就代表一层文件目录。
    1.2 举例:
    举例一:
    某航运软件系统包括:一组域对象、GUI和reports子系统
    在这里插入图片描述

举例二:MVC设计模式
在这里插入图片描述

1.3 JDK中的主要包介绍:

在这里插入图片描述

  1. import的使用:
    import:导入
    1. 在源文件中显式的使用import结构导入指定包下的类、接口
    1. 声明在包的声明和类的声明之间
    1. 如果需要导入多个结构,则并列写出即可
    1. 可以使用"xxx.*"的方式,表示可以导入xxx包下的所结构
    1. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
    1. 如果使用的类或接口是本包下定义的,则可以省略import结构
    1. 如果在源文件中,使用了不同包下的同名的类,则必须至少一个类需要以全类名的方式显示。
    1. 使用"xxx.*"方式表明可以调用xxx包下的所结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入
    1. import static:导入指定类或接口中的静态结构:属性或方法。

浅拷贝和深拷贝

浅拷贝(Shallow Copy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
具体模型如图所示:可以看到基本数据类型的成员变量,对其值创建了新的拷贝。而引用数据类型的成员变量的实例仍然是只有一份,两个对象的该成员变量都指向同一个实例。

List<SMSS_staff_lib> temps = new ArrayList<>();
CollectionUtils.addAll(temps, new SMSS_staff_lib[staffs.size()]);
Collections.copy(temps, staffs);

浅拷贝的实现方式主要有三种:
一、通过拷贝构造方法实现浅拷贝:
拷贝构造方法指的是该类的构造方法参数为该类的对象。使用拷贝构造方法可以很好地完成浅拷贝,直接通过一个现有的对象创建出与该对象属性相同的新的对象。

二、通过重写clone()方法进行浅拷贝:
Object类是类结构的根类,其中有一个方法为protected Object clone() throws CloneNotSupportedException,这个方法就是进行的浅拷贝。有了这个浅拷贝模板,我们可以通过调用clone()方法来实现对象的浅拷贝。但是需要注意:1、Object类虽然有这个方法,但是这个方法是受保护的(被protected修饰),所以我们无法直接使用。2、使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException。对于这两点,我们的解决方法是,在要使用clone方法的类中重写clone()方法,通过super.clone()调用Object类中的原clone方法。

深拷贝的实现方法主要有两种:

一、通过重写clone方法来实现深拷贝
与通过重写clone方法实现浅拷贝的基本思路一样,只需要为对象图的每一层的每一个对象都实现Cloneable接口并重写clone方法,最后在最顶层的类的重写的clone方法中调用所有的clone方法即可实现深拷贝。简单的说就是:每一层的每个对象都进行浅拷贝=深拷贝。

二、通过对象序列化实现深拷贝
虽然层次调用clone方法可以实现深拷贝,但是显然代码量实在太大。特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。
将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。

5_面向对象-中

面向对象的特征二:继承性

1.为什么要有类的继承性?(继承性的好处)

  • ① 减少了代码的冗余,提高了代码的复用性
  • ② 便于功能的扩展
  • ③ 为之后多态性的使用,提供了前提
    图示:
    在这里插入图片描述

2.继承性的格式:
class A extends B{}

  • A:子类、派生类、subclass
  • B:父类、超类、基类、superclass

3.子类继承父类以后有哪些不同?
3.1体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。

  • 特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私的结构。只因为封装性的影响,使得子类不能直接调用父类的结构而已。
    3.2 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。
  • 子类和父类的关系,不同于子集和集合的关系。
  • extends:延展、扩展

4.Java中继承性的说明
1.一个类可以被多个子类继承。
2.Java中类的单继承性:一个类只能有一个父类
3.子父类是相对的概念。
4.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
5.子类继承父类以后,就获取了直接父类以及所间接父类中声明的属性和方法

图示:
在这里插入图片描述

5.java.lang.Object类的理解

  1. 如果我们没显式的声明一个类的父类的话,则此类继承于java.lang.Object类
  2. 所的java类(除java.lang.Object类之外都直接或间接的继承于java.lang.Object类
  3. 意味着,所的java类具有java.lang.Object类声明的功能。

方法的重写

1.什么是方法的重写(override 或 overwrite)?
子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作.

  1. 应用:
    重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。
    3.举例:
    class Circle{
    public double findArea(){}//求面积
    }
    class Cylinder extends Circle{
    public double findArea(){}//求表面积
    }

class Account{
public boolean withdraw(double amt){}
}
class CheckAccount extends Account{
public boolean withdraw(double amt){}
}

4.重写的规则:(先方法名,一样的话看形参,方法名+形参唯一的确定一个方法)
方法的声明: 权限修饰符>= 返回值类型<= 方法名(形参列表) throws 异常的类型{

  •     (Xprivate) 			//方法体
    
  •  			}
    
  •  约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法
    
  •  ① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
    
  •     ② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符 >=
    
  •  	>特殊情况:子类不能重写父类中声明为private权限的方法
    
  •     ③ 返回值类型:
    
  •  	>父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
    
  •  	>父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类<=
    
  •  	>父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
    
  •  ④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理时候讲)
    

  • 子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写,要么都声明为static的(不是重写)。

5.面试题:
区分方法的重写和重载?
答:
① 二者的概念:
② 重载和重写的具体规则
③ 重载:不表现为多态性。
重写:表现为多态性。
重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。
所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;

而对于多态,只等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。

引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。”

关键字:super

1.super 关键字可以理解为:父类的
2.可以用来调用的结构:
属性、方法、构造器
3.super调用属性、方法:
3.1 我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。

4.super调用构造器:
4.1 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行!
4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)“只能二一,不能同时出现
4.4 在构造器的首行,没显式的声明"this(形参列表)“或"super(形参列表)”,则默认调用的是父类中空参的构造器:super()
4.5 在类的多个构造器中,至少一个类的构造器中使用了"super(形参列表)”,调用父类中的构造器

子类对象实例化全过程

理解即可。
1.从结果上看:继承性

子类继承父类以后,就获取了父类中声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所父类中声明的属性。
2.从过程上看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,…直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所的父类的结构,所以才可以看到内存中父类中的结构,子类对象才可以考虑进行调用。调用父类的构造器了,需要把父类的属性和方法加载到内存中

图示:
在这里插入图片描述

3.强调说明:
虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。

在这里插入图片描述

面向对象的特征三:多态性

1.多态性的理解:可以理解为一个事物的多种形态。
2.何为多态性:
对象的多态性:父类引用指向子类的对象(或子类的对象赋给父类的引用)
举例:
//当调用子父类同名同参数的方法是,实际执行的是子类重写父类的方法—虚拟方法调用
Person p = new Man();
//多态使用后,只能调用子类重写的方法,不能调用子类特有的方法
Object obj = new Date();
3.多态性的使用:虚拟方法调用(多态情况下)
子类中重写了父类的方法,此时父类的方法叫做虚拟方法,父类根据给他的不同子类对象,动态地调用子类的方法,这样的方法在编译期无法确定。

有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
总结:编译,看左边;运行,看右边。
4.多态性的使用前提:
① 类的继承关系 ② 方法的重写
5.多态性的应用举例:
举例一:
public void func(Animal animal){//Animal animal = new Dog();
animal.eat();
animal.shout();
}
举例二:
public void method(Object obj){

}

举例三:
class Driver{

public void doData(Connection conn){//conn = new MySQlConnection(); / conn = new OracleConnection();
	//规范的步骤去操作数据

// conn.method1();
// conn.method2();
// conn.method3();

}

}

6.多态性使用的注意点:
对象的多态性,只适用于方法,不适用于属性(属性编译和运行都看左边)


7.关于向上转型与向下转型:
7.1 向上转型:多态
7.2 向下转型:
7.2.1 为什么使用向下转型:
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类(特有的)特有的属性和方法不能调用。如何才能调用子类特有的属性和方法?使用向下转型。
7.2.2 如何实现向下转型:
使用强制类型转换符:()
7.2.3 使用时的注意点:
① 使用强转时,可能出现ClassCastException的异常。
② 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
7.2.4 instanceof的使用:
① a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
② 如果 a instanceof A返回true,则 a instanceof B也返回true.其中,类B是类A的父类。
③ 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。
7.2.5 图示:
在这里插入图片描述

  1. 面试题:
    8.1 谈谈你对多态性的理解?
    ① 实现代码的通用性。
    ② Object类中定义的public boolean equals(Object obj){ }
    JDBC:使用java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server)
    ③ 抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)
    8.2 多态是编译时行为还是运行时行为?
    C++中的虚函数、纯虚函数区别和联系
    虚函数和纯虚函数有以下所示方面的区别。
    (1)类里如果声明了虚函数,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被覆盖,这样的话,这样编译器就可以使用后期绑定来达到多态了。纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。
    (2)虚函数在子类里面也可以不重载的;但纯虚函数必须在子类去实现,这就像Java的接口一样。通常把很多函数加上virtual,是一个好的习惯,虽然牺牲了一些性能,但是增加了面向对象的多态性,因为很难预料到父类里面的这个函数不在子类里面不去修改它的实现。
    (3)虚函数的类用于“实作继承”,继承接口的同时也继承了父类的实现。当然大家也可以完成自己的实现。纯虚函数关注的是接口的统一性,实现由子类完成。
    (4)带纯虚函数的类叫虚基类,这种基类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。这样的类也叫抽象类。抽象类和大家口头常说的虚基类还是有区别的,在C#中用abstract定义抽象类,而在C++中有抽象类的概念,但是没有这个关键字。抽象类被继承后,子类可以继续是抽象类,也可以是普通类,而虚基类,是含有纯虚函数的类,它如果被继承,那么子类就必须实现虚基类里面的所有纯虚函数,其子类不能是抽象类。
    纯虚函数
    声明了纯虚函数的类是一个抽象类。所以,用户不能创建类的实例,只能创建它的派生类的实例。
    纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。
    定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。
    纯虚函数的意义,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。
    顺便说一句,为一个纯虚函数提供定义也是可能的。也就是说,你可以为纯虚函数提供实现,C++编译器也不会阻拦(DEV_CPP中G++(gcc 3.4.2)编译器并不支持为纯虚函数定义缺省行为;在VC6.0支持为纯虚函数定义缺省的实现,派生类的虚函数override基类的纯虚函数),但调用它的唯一方式是通过类名完整地指明是哪个调用(如:pb->Base:: pureVirtual())。
    有时,声明一个除纯虚函数外什么也不包含的类很有用。这样的类叫协议类(Protocol class),它为派生类仅提供函数接口,完全没有实现。
    虚函数(在此指的是非纯虚函数)
    虚函数的情况和纯虚函数有点不一样。照例,派生类继承了函数的接口,但简单虚函数一般还提供了实现,派生类可以选择改写(override)它们或不改写它们。
    声明虚函数的目的在于,使派生类继承函数的接口和缺省实现。
    虚函数的意义,每个类必须提供一个可以被调用的虚函数,但每个类可以按它们认为合适的任何方式处理。如果某个类不想做什么特别的事,可以借助于基类中提供的缺省处理函数。也就是说,虚函数的声明是在告诉子类的设计者,”你必须支持虚函数,但如果你不想写自己的版本,可以借助基类中的缺省版本。”
    实际上,为虚函数同时提供函数声明和缺省实现是很危险的。(当你增加一个派生类继承基类时,必须小心使用虚函数,满足派生类特有的需求,否则就是调用基类的虚函数,可能引起错误)
    非虚函数
    最后,来谈谈类的非虚函数,当一个成员函数为非虚函数时,它在派生类中的行为就不应该不同。实际上,非虚成员函数表明了一种特殊性上的不变性,因为它表示的是不会改变的行为――不管一个派生类有多特殊。
    声明非虚函数的目的在于,使派生类继承函数的接口和强制性实现。(所有的派生类都应该完成的使用该函数完成某一个功能)
    建议
    结合前面的学过的,再次强调一下,如果你没有为类设计虚函数(纯虚函数),该类一般来说应该不具有继承特性(除非确实的存在IS-A关系,即便存在,派生类也没有了特殊性,这种情况一般是设计中抽象的不合理)。当然除了Protocol class也不应该把类的成员函数全部设计成虚函数(纯虚函数),这也说明了类设计的不合理(不能正确的抽象出基类、派生类之间不变的部分)。
    c++中没有接口的概念,与之对应的是纯虚类,即只含有纯虚函数的类,c++抽象类的概念是含有纯虚函数成员的类。这是因为c++提供多继承,而像 java、c#这些只提供单继承(避免多继承的复杂性和低效性)的语言为了模拟多继承功能就提供了接口概念,接口可以继承多个。
    abstract class是抽象类,至少包含一个纯虚函数的类就叫做抽象类。
    但是如果一个类,所有的成员都是纯虚函数,那么它和一般的抽象类在用法上是有区别的。至少Microsoft给的COM接口定义全部都是仅由纯虚函数构成的类。因此把这样的类定义叫做纯虚类也不算错。
    纯虚函数和虚函数的区别在于前者不包含定义,而后者包含函数体。
    那么纯虚类就是不包含任何实现(包括成员函数定义和成员变量定义。前者代表算法,后者代表结构)。不包含任何算法和结构的类叫做纯虚类,应该没有问题。
    在Java里面的确没有纯虚类的概念,因为Java里没有纯虚函数这个概念。Java管虚函数叫做abstract function,管抽象类叫做abstract class,直接说来,Java根本没有virtual这个关键字,都用abstract代替,因此Java里面根本就没有Pure这个概念。有那就是 interface。在interface里面定义的函数都不能有函数体,这个在Java里面叫做接口。那么C++里面与interface等同的概念就 是纯虚类了,C++用纯虚类来模拟interface这个抽象概念,因此这里说的“纯虚类”与Java的abstract class不同,与C++的一般抽象类也不同。“纯虚类”与C++一般抽象类的区别就好比Java里面interface 和 abstract class的区别。
    2、抽象类:
    抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。
    ⑴抽象类的定义:
    称带有纯虚函数的类为抽象类。
    ⑵抽象类的作用:
    抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。所 以派生类实际上刻画了一组子类的操作接口的通用语义,这些语义也传给子类,子类可以具体实现这些语义,也可以再将这些语义传给自己的子类。
    (3)使用抽象类时注意:
    • 抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。
    • 抽象类是不能定义对象的。
    abstract不是c++的关键词,是微软自己的发明,用来提供.net支持 。VC++并不规范,笔者用devcpp做程序设计,无abstract关键字
    至于抽象类确实一个类中有纯虚函数就是抽象类 。CSDN中关于C++中abstract关键字的介绍应该是微软扩展出来的,编译器不支持abstract关键字。

Object类的使用

1.java.lang.Object类的说明:

  • 1.Object类是所有Java类的根父类
  • 2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
  • 3.Object类中的功能(属性、方法)就具通用性。
  • 属性:无
  • 方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()
  • wait() 、 notify()、notifyAll()
    
    1. Object类只声明了一个空参的构造器
      2.equals()方法
      2.1 equals()的使用:
    2. 是一个方法,而非运算符
    1. 只能适用于引用数据类型
    1. Object类中equals()的定义:
  • public boolean equals(Object obj) {
    return (this == obj);
    }
  • 说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
    1. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是
  • 两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
    1. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们
  • 就需要对Object类中的equals()进行重写.
  • 重写的原则:比较两个对象的实体内容是否相同.
    2.2 如何重写equals()
    2.2.1 手动重写举例:
    class User{
    String name;
    int age;
    //重写其equals()方法
    public boolean equals(Object obj){
    if(obj == this){
    return true;
    }
    if(obj instanceof User){
    User u = (User)obj;
    return this.age == u.age && this.name.equals(u.name);
    }
    return false;
    }
    }
    2.2.2 开发中如何实现:自动生成的
    2.3 回顾 == 运算符的使用:
  • == :运算符
    1. 可以使用在基本数据类型变量和引用数据类型变量中
    1. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
  • 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
  • 补充: == 符号使用时,必须保证符号左右两边的变量类型一致。
  1. toString()方法
    3.1 toString()的使用:
    1. 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
    1. Object类中toString()的定义:
  • public String toString() {
    return getClass().getName() + “@” + Integer.toHexString(hashCode());
    }
    1. 像String、Date、File、包装类等都重写了Object类中的toString()方法。
  • 使得在调用对象的toString()时,返回"实体内容"信息
    1. 自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"
      3.2 如何重写toString()
      举例:
      //自动实现
      @Override
      public String toString() {
      return “Customer [name=” + name + “, age=” + age + “]”;
      }

4.面试题:
① final、finally、finalize的区别?
② == 和 equals() 区别

单元测试方法

  • Java中的JUnit单元测试
  • 步骤:
  • 1.中当前工程 - 右键择:build path - add libraries - JUnit 4 - 下一步
  • 2.创建Java类,进行单元测试。
  • 此时的Java类要求:① 此类是public的 ②此类提供公共的无参的构造器
  • 3.此类中声明单元测试方法。
  • 此时的单元测试方法:方法的权限是public,没返回值,没形参
  • 4.此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;
  • 5.声明好单元测试方法以后,就可以在方法体内测试相关的代码。
  • 6.写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test
  • 说明:
  • 1.如果执行结果没任何异常:绿条
  • 2.如果执行结果出现异常:红条

包装类的使用

1.为什么要有包装类(或封装类)
为了使基本数据类型的变量具有类的特征,引入包装类。

2.基本数据类型与对应的包装类:
在这里插入图片描述

3.需要掌握的类型间的转换:(基本数据类型、包装类、String)
在这里插入图片描述

简易版:
基本数据类型<—>包装类:JDK 5.0 新特性:自动装箱 与自动拆箱
基本数据类型、包装类—>String:调用String重载的valueOf(Xxx xxx) String s=i+""; (i是int)
String—>基本数据类型、包装类:调用包装类的parseXxx(String s)
注意:转换时,可能会报NumberFormatException
应用场景举例:
① Vector类中关于添加元素,只定义了形参为Object类型的方法:
v.addElement(Object obj); //基本数据类型 —>包装类 —>使用多态

equals和==

== :运算符

    1. 可以使用在基本数据类型变量和引用数据类型变量中
    1. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
  • 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
  • 补充: == 符号使用时,必须保证符号左右两边的变量类型一致。

equals是一个方法,而非运算符

    1. 只能适用于引用数据类型
    1. Object类中equals()的定义:
  • public boolean equals(Object obj) {
    return (this == obj);
    }
  • 说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
    1. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是
  • 两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
    1. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们
  • 就需要对Object类中的equals()进行重写.
  • 重写的原则:比较两个对象的实体内容是否相同.

6_面向对象-下

关键字:static

static:静态的
1.可以用来修饰的结构:主要用来修饰类的内部结构
属性、方法、代码块、内部类
2.static修饰属性:静态变量(或类变量)
2.1 属性,是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)

  •     实例变量:我们创建了类的多个对象,每个对象都独立的拥一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
    
  •       静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
    
  •  2.2 static修饰属性的其他说明:
    
  •   ① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
    
  •      ② 静态变量的加载要早于对象的创建。
    
  •      ③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
    
  •      ④		类变量	实例变量
    
  •      类		yes		no
    
  •      对象	yes		yes
    
  •     2.3 静态属性举例:System.out; Math.PI;
    

3.静态变量内存解析:
在这里插入图片描述

4.static修饰方法:静态方法、类方法
① 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
② 静态方法 非静态方法

  •      类		    yes		no
    
  •      对象		yes		yes
    

③ 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

  1. static的注意点:
    5.1 在静态的方法内,不能使用this关键字、super关键字。变量(类.变量)
    5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。

6.如何判定属性和方法应该使用static关键字:
6.1 关于属性

属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
类中的常量也常常声明为static

6.2 关于方法

操作静态属性的方法,通常设置为static的(get/set方法)
工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections
7.使用举例:
举例一:Arrays、Math、Collections等工具类
举例二:单例模式
举例三:
class Circle{

private double radius;
private int id;//自动赋值

public Circle(){
	id = init++;
	total++;
}

public Circle(double radius){
	this();

// id = init++;
// total++;
this.radius = radius;

}

private static int total;//记录创建的圆的个数
private static int init = 1001;//static声明的属性被所对象所共享

public double findArea(){
	return 3.14 * radius * radius;
}

public double getRadius() {
	return radius;
}

public void setRadius(double radius) {
	this.radius = radius;
}

public int getId() {
	return id;
}

public static int getTotal() {
	return total;
}

}

单例模式

1.设计模式的说明
1.1 理解

设计模式是在大量的实践中总结和理论化之后优的代码结构、编程风格、以及解决问题的思考方式。

1.2 常用设计模式 — 23种经典的设计模式 GOF
创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

2.单例模式
2.1 要解决的问题:
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
2.2 具体代码的实现:
饿汉式1:
class Bank{

//1.私化类的构造器
private Bank(){
	
}

//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Bank instance = new Bank();

//3.提供公共的静态的方法,返回类的对象
public static Bank getInstance(){
	return instance;
}

}

饿汉式2:使用了静态代码块。上来就new
class Order{

//1.私化类的构造器
private Order(){
	
}

//2.声明当前类对象,没初始化
//4.此对象也必须声明为static的
private static Order instance = null;

static{
	instance = new Order();

}

//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
	return instance;
}

}
懒汉式:用到再new
class Order{

//1.私化类的构造器
private Order(){
	
}

//2.声明当前类对象,没初始化
//4.此对象也必须声明为static的
private static Order instance = null;

//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
	
	if(instance == null){
		
		instance = new Order();
		
	}
	return instance;
}

}
2.3 两种方式的对比:

  • 饿汉式:
  •  坏处:对象加载时间过长。
    
  •  好处:饿汉式是线程安全的
    
  • 懒汉式:好处:延迟对象的创建。
  •    目前的写法坏处:线程不安全。--->到多线程内容时,再修改
    

main()的使用说明

    1. main()方法作为程序的入口
    1. main()方法也是一个普通的静态方法
    1. main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)

如何将控制台获取的数据传给形参:String[] args?
运行时:java 类名 “Tom” “Jerry” “123” “true”

sysout(args[0]);//“Tom”
sysout(args[3]);//“true” -->Boolean.parseBoolean(args[3]);
sysout(args[4]);//报异常

小结:一叶知秋
public static void main(String[] args){//方法体}

权限修饰符:private 缺省 protected pubilc ---->封装性
修饰符:static \ final \ abstract \native 可以用来修饰方法
返回值类型: 无返回值 / 有返回值 -->return
方法名:需要满足标识符命名的规则、规范;“见名知意”
形参列表:重载 vs 重写;参数的值传递机制;体现对象的多态性
方法体:来体现方法的功能

main(){
Person p = new Man();
p.eat();
//p.earnMoney();

Man man = new Man();
man.eat();
man.earnMoney();
}

类的结构:代码块

类的成员之四:代码块(初始化块)(重要性较属性、方法、构造器差一些)
1.代码块的作用:用来初始化类、对象的信息
2.分类:代码块要是使用修饰符,只能使用static
分类:静态代码块 vs 非静态代码块
3.
静态代码块:

内部可以输出语句
随着类的加载而加载且执行,而且只执行一次
作用:初始化类的信息
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

非静态代码块:

内部可以输出语句
随着对象的创建而加载且执行
每创建一个对象,就执行一次非静态代码块
作用:可以在创建对象时,对对象的属性等进行初始化
如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

  1. 实例化子类对象时,涉及到父类、子类中静态代码块、非静态代码块、构造器的加载顺序:
    对应的练习:LeafTest.java / Son.java
    由父及子,静态先行。

属性的赋值顺序

  • ①默认初始化
  • ②显式初始化/⑤在代码块中赋值(按顺序判断是2还是5)
  • ③构造器中初始化
  • ④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
  • 执行的先后顺序:① - ② / ⑤ - ③ - ④

关键字:final

final:最终的
1.可以用来修饰:类、方法、变量

2.具体的:

2.1 final 用来修饰一个类:此类不能被其他类所继承。

  •      比如:String类、System类、StringBuffer类
    

2.2 final 用来修饰方法:表明此方法不可以被重写

  •  	比如:Object类中getClass();
    

2.3 final 用来修饰变量:此时的"变量"就称为是一个常量

  •  1. final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化
    
  •  2. final修饰局部变量:
    
  •    尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
    

static final 用来修饰属性:全局常量

关键字:abstract

abstract: 抽象的(不让实例化)
1.可以用来修饰:类、方法
2.具体的:
abstract修饰类:抽象类

  •  > 此类不能实例化
    
  •  > 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
    
  •  > 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作 --->抽象的使用前提:继承性
    

abstract修饰方法:抽象方法

  •  > 抽象方法只方法的声明,没方法体
    
  •  > 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
    
  •    > 若子类重写了父类中的所的抽象方法后,此子类方可实例化
    
  •      若子类没重写父类中的所的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
    

3.注意点:

  • 1.abstract不能用来修饰:属性、构造器等结构
  • 2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类

4.abstract的应用举例:
举例一:
在这里插入图片描述

举例二:
abstract class GeometricObject{
public abstract double findArea();
}
class Circle extends GeometricObject{
private double radius;
public double findArea(){
return 3.14 * radius * radius;
};
}
举例三:IO流中设计到的抽象类:InputStream/OutputStream / Reader /Writer。在其内部
定义了抽象的read()、write()方法。

模板方法的设计模式

  1. 解决的问题

在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变
部分可以抽象出来,供不同子类实现。这就是一种模板模式。

  1. 举例
    abstract class Template{

    //计算某段代码执行所需要花费的时间
    public void spendTime(){

     long start = System.currentTimeMillis();
     
     this.code();//不确定的部分、易变的部分
     
     long end = System.currentTimeMillis();
     
     System.out.println("花费的时间为:" + (end - start));
    

    }

    public abstract void code();

}

class SubTemplate extends Template{

@Override
public void code() {
	
	for(int i = 2;i <= 1000;i++){
		boolean isFlag = true;
		for(int j = 2;j <= Math.sqrt(i);j++){
			
			if(i % j == 0){
				isFlag = false;
				break;
			}
		}
		if(isFlag){
			System.out.println(i);
		}
	}

}

}

  1. 应用场景
    在这里插入图片描述

匿名

匿名对象-new Person();
抽象类的匿名子类
Person p=new Person(){
//重写abstract的方法
void f(){
System.out.println(“我是一个抽象类的匿名子类”);
}
}
abstract Public Person{
abstract void f();
}
3. 匿名子类的匿名对象
method(new Person(){
void f(){
System.out.println(“我是一个抽象类的匿名子类”);
}
})
void method(Person p){}

关键字:interface

interface:接口
1.使用说明:类和子类(Son is a Father) 接口(相同的特征—手机类有USB,电脑有USB)
1.接口使用interface来定义

  • 2.Java中,接口和类是并列的两个结构
  • 3.如何定义接口:定义接口中的成员
  •  3.1 JDK7及以前:只能定义全局常量和抽象方法
    
  •  	>全局常量:public static final的.但是书写时,可以省略不写
    
  •  	>抽象方法:public abstract的
    
  •  3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略
    
    1. 接口中不能定义构造器的!意味着接口不可以实例化
  • 抽象类的构造器是让抽象类的子类实例化用的
    1. Java开发中,接口通过让类去实现(implements)的方式来使用.
  • 如果实现类覆盖了接口中的所抽象方法,则此实现类就可以实例化
  • 如果实现类没覆盖接口中所的抽象方法,则此实现类仍为一个抽象类
    1. Java类可以实现多个接口 —>弥补了Java单继承性的局限性
  • 格式:class AA extends BB implements CC,DD,EE
    1. 接口与接口之间可以继承,而且可以多继承

    1. 接口的具体使用,体现多态性
    1. 接口,实际上可以看做是一种规范

2.举例:
在这里插入图片描述

class Computer{

public void transferData(USB usb){//USB usb = new Flash();
	usb.start();
	
	System.out.println("具体传输数据的细节");
	
	usb.stop();
}

}

interface USB{
//常量:定义了长、宽、最大最小的传输速度等

void start();

void stop();

}

class Flash implements USB{

@Override
public void start() {
	System.out.println("U盘开启工作");
}

@Override
public void stop() {
	System.out.println("U盘结束工作");
}

}

class Printer implements USB{
@Override
public void start() {
System.out.println(“打印机开启工作”);
}

@Override
public void stop() {
	System.out.println("打印机结束工作");
}

}
体会:

  • 1.接口使用上也满足多态性
  • 2.接口,实际上就是定义了一种规范
  • 3.开发中,体会面向接口编程!
    3.体会面向接口编程的思想
    在这里插入图片描述

面向接口编程:我们在应用程序中,调用的结构都是JDBC中定义的接口,不会出现具体某一个
数据库厂商的API。
4.Java8中关于接口的新规范
//知识点1:接口中定义的静态方法,只能通过接口来调用。

//知识点2:通过实现类的对象,可以调用接口中的默认方法。
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法

//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法。–>类优先原则
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没重写此方法的情况下,报错。–>接口冲突。
//这就需要我们必须在实现类中重写此方法
//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
5.面试题:
抽象类和接口的异同?
相同点:不能实例化;都可以包含抽象方法的。
不同点:
1)把抽象类和接口(java7,java8,java9)的定义、内部结构解释说明
2)类:单继承性 接口:多继承
类与接口:多实现

代理模式

  1. 解决的问题

代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。

  1. 举例
    interface NetWork{

    public void browse();

}

//被代理类
class Server implements NetWork{

@Override
public void browse() {
	System.out.println("真实的服务器访问网络");
}

}
//代理类
class ProxyServer implements NetWork{

private NetWork work;

public ProxyServer(NetWork work){
	this.work = work;
}


public void check(){
	System.out.println("联网之前的检查工作");
}

@Override
public void browse() {
	check();
	
	work.browse();
	
}

}

  1. 应用场景
    在这里插入图片描述

工厂的设计模式

  1. 解决的问题
    实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

  2. 具体模式

简单工厂模式:用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)
工厂方法模式:用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)

类的结构:内部类

内部类:类的第五个成员
1.定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类.
2.内部类的分类:
成员内部类(静态、非静态 ) vs 局部内部类(方法内、代码块内、构造器内)
3.成员内部类的理解:
一方面,作为外部类的成员:

  •  	>调用外部类的结构
    
  •  	>可以被static修饰
    
  •  	>可以被4种不同的权限修饰
    

另一方面,作为一个类:

  •  	> 类内可以定义属性、方法、构造器等
    
  •  	> 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
    
  •  	> 可以被abstract修饰
    

4.成员内部类:
4.1如何创建成员内部类的对象?(静态的,非静态的)
//创建静态的Dog内部类的实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();

//创建非静态的Bird内部类的实例(非静态的成员内部类):
//Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();

4.2如何在成员内部类中调用外部类的结构?
class Person{
String name = “小明”;
public void eat(){
}
//非静态成员内部类
class Bird{
String name = “杜鹃”;
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
//Person.this.eat();
}
}
}
5.局部内部类的使用:
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){

	//创建一个实现了Comparable接口的类:局部内部类
	//方式一:

// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();

	//方式二:
	return new Comparable(){

		@Override
		public int compareTo(Object o) {
			return 0;
		}
		
	};
	
}

注意点:
在局部内部类的方法中(比如:show如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,要求此局部变量声明为final的。
*
jdk 7及之前版本:要求此局部变量显式的声明为final的
jdk 8及之后的版本:可以省略final的声明
总结:
成员内部类和局部内部类,在编译以后,都会生成字节码文件。
格式:成员内部类:外部类 内 部 类 名 . c l a s s 局 部 内 部 类 : 外 部 类 内部类名.class 局部内部类:外部类 .class数字 内部类名.class

7_异常处理

异常

  1. 异常的体系结构
  • java.lang.Throwable
  •  |-----java.lang.Error:一般不编写针对性的代码进行处理。
    
  •  |-----java.lang.Exception:可以进行异常的处理
    
  •  	|------编译时异常(checked)
    
  •  			|-----IOException
    
  •  				|-----FileNotFoundException
    
  •  			|-----ClassNotFoundException
    
  •  	|------运行时异常(unchecked,RuntimeException)
    
  •  			|-----NullPointerException
    
  •  			|-----ArrayIndexOutOfBoundsException
    
  •  			|-----ClassCastException
    
  •  			|-----NumberFormatException
    
  •  			|-----InputMismatchException
    
  •  			|-----ArithmeticException
    

在这里插入图片描述

2.从程序执行过程,看编译时异常和运行时异常
在这里插入图片描述

编译时异常:执行javac.exe命名时,可能出现的异常
运行时异常:执行java.exe命名时,出现的异常

3.常见的异常类型,请举例说明:
//以下是运行时异常*********
//ArithmeticException
@Test
public void test6(){
int a = 10;
int b = 0;
System.out.println(a / b);
}

//InputMismatchException
@Test
public void test5(){
	Scanner scanner = new Scanner(System.in);
	int score = scanner.nextInt();
	System.out.println(score);
	
	scanner.close();
}

//NumberFormatException
@Test
public void test4(){
	
	String str = "123";
	str = "abc";
	int num = Integer.parseInt(str);
	
	
	
}

//ClassCastException
@Test
public void test3(){
	Object obj = new Date();
	String str = (String)obj;
}

//IndexOutOfBoundsException
@Test
public void test2(){
	//ArrayIndexOutOfBoundsException

// int[] arr = new int[10];
// System.out.println(arr[10]);
//StringIndexOutOfBoundsException
String str = “abc”;
System.out.println(str.charAt(3));
}

//NullPointerException
@Test
public void test1(){

// int[] arr = null;
// System.out.println(arr[3]);

	String str = "abc";
	str = null;
	System.out.println(str.charAt(0));
	
}

//******************以下是编译时异常***************************
@Test
public void test7(){

// File file = new File(“hello.txt”);
// FileInputStream fis = new FileInputStream(file);
//
// int data = fis.read();
// while(data != -1){
// System.out.print((char)data);
// data = fis.read();
// }
//
// fis.close();

}

异常的处理

1.java异常处理的抓抛模型
过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。

  •       并将此对象抛出。
    
  •       一旦抛出对象以后,其后的代码就不再执行。
    
  •  关于异常对象的产生:① 系统自动生成的异常对象
    
  •  			     ② 手动的生成一个异常对象,并抛出(throw)
    

过程二:“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws

2.异常处理方式一:try-catch-finally
2.1 使用说明:
try{

  •  //可能出现异常的代码
    
  • }catch(异常类型1 变量名1){
  •  //处理异常的方式1
    
  • }catch(异常类型2 变量名2){
  •  //处理异常的方式2
    
  • }catch(异常类型3 变量名3){
  •  //处理异常的方式3
    
  • }
  • finally{
  •  //一定会执行的代码
    
  • }
  • 说明:
    1. finally是可选的。
    1. 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配
    1. 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没写finally的情况。继续执行其后的代码
    1. catch中的异常类型如果没子父类关系,则谁声明在上,谁声明在下无所谓。
  • catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
    1. 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
    1. 在try结构中声明的变量,再出了try结构以后,就不能再被调用
    1. try-catch-finally结构可以嵌套

总结:如何看待代码中的编译时异常和运行时异常?

  • 体会1:使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
  • 体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。
    2.2:finally的再说明:
  • 1.finally是可选的
  • 2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中return语句,catch中return语句等情况。
  • 3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

2.3:[面试题]

final、finally、finalize三者的区别?

类似:
throw 和 throws
Collection 和 Collections
String 、StringBuffer、StringBuilder
ArrayList 、 LinkedList
HashMap 、LinkedHashMap
重写、重载

结构不相似的:
抽象类、接口
== 、 equals()
sleep()、wait()

3.异常处理方式二:
"throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码,就不再执行!

  1. 对比两种处理方式
    try-catch-finally:真正的将异常给处理掉了。
    throws的方式只是将异常抛给了方法的调用者。并没真正将异常处理掉。

  2. 体会开发中应该如何选择两种处理方式?

  • 5.1 如果父类中被重写的方法没throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中异常,必须使用try-catch-finally方式处理。
  • 5.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。

补充:
方法重写的规则之一:
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型

手动抛出异常对象

1.使用说明
在程序执行中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常类的对象。

2.[面试题]
throw 和 throws区别:
throw 表示抛出一个异常类的对象,生成异常对象的过程。声明在方法体内。
throws 属于异常处理的一种方式,声明在方法的声明处。

3.典型例题
class Student{

private int id;

public void regist(int id) throws Exception {
	if(id > 0){
		this.id = id;
	}else{
		//手动抛出异常对象

// throw new RuntimeException(“您输入的数据非法!”);
// throw new Exception(“您输入的数据非法!”);
throw new MyException(“不能输入负数”);

	}
	
}

@Override
public String toString() {
	return "Student [id=" + id + "]";
}

}

自定义异常类

如何自定义一个异常类?
/*

  • 如何自定义异常类?
    1. 继承于现的异常结构:RuntimeException 、Exception
    1. 提供全局常量:serialVersionUID
    1. 提供重载的构造器

*/
public class MyException extends Exception{

static final long serialVersionUID = -7034897193246939L;

public MyException(){
	
}

public MyException(String msg){
	super(msg);
}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值