目录
打开DOS命令窗口,执行java HelloWorld。执行原理?
ClassLoader是在哪个位置上搜索HelloWorld.class字节码文件的?
标识符的命名规则?【不按照这个规则来,编译器会报错,这是语法】
标识符的命名规范?【只是一种规范,不属于语法,不遵守规范编译器不会报错】
方法在执行过程当中,在JVM中的内存是如何分配的?内存是如何变化的?
面向对象【Java语言的核心机制,最重要的内容,Java语言的特色】
关于Java语言当中方法的覆盖(Override【官方的】/Overwrite)
public boolean equals(Object obj); *
getMessage()和printStackTrace()
StringBuffer和StringBuilder是什么?
StringBuffer, StringBuilder和String最大的区别?
如何优化StringBuffer和StringBuilder?
StringBuffer和StringBuilder的区别?
自动装箱(auto_boxing)和自动拆箱(auto_unboxing)
boolean add(Object), void clear(), boolean isEmpty()
打开DOS命令窗口,执行java HelloWorld。执行原理?
- Java.exe命令会启动JVM
- JVM启动后会启动类加载器classLoder
- ClassLoader会在硬盘上的某个位置搜索HelloWorld.class字节码文件
- 找到该文件则执行
- 找不到该文件则报错
ClassLoader是在哪个位置上搜索HelloWorld.class字节码文件的?
- 默认情况下,ClassLoader从当前路径下加载xxx.class字节码文件
- 当然,也可以让ClassLoader从当前路径下加载字节码文件,这时需要配置环境变量classpath
- Classpath是给ClassLoader类加载器指路的
- Classpath环境变量没有配置的话,类加载器默认从当前路径下找字节码文件,当classpath环境变量配置为某个指定的路径之后,类加载器只去指定的路径当中加载字节码文件。所以每一次执行.class程序的时候,需要在DOS命令窗口中先切换到.class字节码文件所在的路径下。然后运行。
- Classpath也可以这样配置:classpath=.
注意:
路径中”..”表示上级目录
路径中”.”表示当前目录
关于JAVA源程序当中的注释:
什么是注释?注释的作用是什么?
- 出现在java的源程序当中,对java源代码的解释说明
- 注释不会被编译到.class字节码文件当中
- 一个好的开发习惯应该是多编写注释,这样程序的可读性比较强
JAVA中的注释怎么写呢?
-
单行注释
//单行注释,只注释当前行
-
多行注释
/*
多行注释
*/
-
javadoc注释
/**
* Javadoc注释
* Javadoc注释
*
*/
注意:这种注释是比较专业的注释,该注释信息会被javadoc.exe工具解析提取并生成帮助文档
需要记忆:
- public
- class
- static
- void
- System.out.println(“”); 向控制台输出消息
- 类体
- 方法体
- 类体中不能直接编写java语句【除了声明之外】
- 一个java语句必须以”;”结束
- 方法体中可以编写多条java语句
- 主方法是程序的入口,固定写法,SUN规定的
Public class和class的区别:
- 一个java源文件中可以定义多个class
- 一个java源文件中不一定有public的class
- 一个class会定义生成一个xxx.class字节码文件
- 一个java源文件当中定义公开的类的话,public的class只能有一个,并且该类名称必须与java源文件名称一致
- 每一个class当中都可以编写main方法,都可以设定程序的入口,想执行B.class中的main方法:java B
- 注意:当在命令窗口中执行java Hello,那么要求Hello.class当中必须有主方法。没有主方法会出现运行阶段的错误
关于JAVA语言当中的标识符:
什么是标识符?
- 在JAVA源程序当中,凡是程序员有权自己命名的单词都是标识符
- 标识符可以标识什么元素呢?
- 类名
- 方法名
- 变量名
- 接口名
- 常量名
- ……
标识符的命名规则?【不按照这个规则来,编译器会报错,这是语法】
- 一个合法的标识符只能由“数字、字母、下划线_、美元符号$”组成。不能含有其他符号
- 不能数字开头
- 严格区分大小写
- 关键字不能做标识符
- 理论上无长度限制,但最好不要太长
标识符的命名规范?【只是一种规范,不属于语法,不遵守规范编译器不会报错】
- 最好见名知意
例:
public class UserService{
public void login(String username, String password){
}
}
- 遵守驼峰命名方式
例:
SystemService
UserService
CustomerService
关于字面值: JavaSelf01
- 类名、接口名:首字母大写,后面每个单词首字母大写
- 变量名、方法名:首字母小写,后面每个单词首字母大写
- 常量名:全部大写
字面值:
- 10、100
- 3.14
- “abc”
- ‘a’
- true、false
字面值就是数据
字面值是JAVA源程序的组成部分之一。包括标识符和关键字它们都是JAVA源程序的组成部分
数据在现实世界中是分门别类的,所以数据在计算机编程语言当中也是有类型的:【数据类型】
- 10、100 属于整数型字面值
- 3.14 属于浮点型字面值
- True、false 属于bool型字面值
- “abv”、“中国人” 属于字符串型字面值
- ‘A’、‘人’ 属于字符型字面值
注意:
- JAVA语言当中所有字符串型字面值必须使用双引号括起来,双引号是半角
- JAVA语言当中所有字符型字面值必须使用单引号括起来,单引号是半角
关于java语言当中的变量:使用所有的基础语法开发系统业务
什么是变量?
- 变量本质上来说是内存中的一块空间,这块空间有数据类型,名字,字面值
- 变量包含三部分:数据类型、名称、字面值【数据】
- 变量是内存中存储数据的最基本的单元
数据类型的作用?
- 不同的数据有不同的类型,不同的数据类型底层会分配不同大小的空间
- 数据类型是指导程序在运行阶段应该分配多大的内存空间
变量中存储的具体的“数据”必须和变量的“数据类型”一致,当不一致的时候编译报错。
声明/定义变量的语法格式:
- 数据类型 变量名:
- 数据类型:目前我们还没有学习数据类型,但有一种数据类型是整数型,叫做int
- 变量名:只要是合法的标识符就行,规范中要求:首字母小写,后面每个单词首字母大写
例如:
Int i;
Int age;
Int length;
Int size;
Int num
其中int是数据类型,I,age,length,size,num都是变量名
变量声明之后怎么赋值?
语法格式:
变量名 = 字面值;
要求:字面值的数据类型必须和变量的数据类型一致。
=等号是一个运算符,叫做赋值运算符,赋值运算符先运算等号右边的表达式,表达式执行结束后的结果赋值给左边的变量。
声明和赋值可以放到一起完成。
例:
int i = 10;
变量赋值之后,可以重新赋值,变量的值可变化:
int i = 10;
i = 20;
i = 100;
有了变量的概念后,内存空间得到了重复的使用
通常访问一个变量包括两种访问方式:
- 读取变量中保存的具体数据 get/获取
- 修改变量中保存的具体数据 set/设置
i = 20;//set
System.out.println(i);//get
变量在一行上可以声明多个,变量必须先声明,再赋值才能访问。
在方法体当中的JAVA代码,是遵守自上而下的顺序依次执行的,逐行运行
特点:第二行的代码必须完整的结束之后,第三行程序才能执行。
在同一个“作用域”当中,变量名不能重名,但是变量可以重新赋值。
变量的作用域
什么是作用域?
- 变量的作用域,其实描述的就是变量的有效范围
- 在什么范围之内是可以被访问的,只要出了这个范围该变量就无法访问了
只要记住一句话:
- 出了大括号就不认识了
关于变量的分类
根据变量声明的位置来分类:
- 局部变量
在方法体当中声明的变量叫做局部变量
- 成员变量
在方法体外【类体之内】声明的变量叫做成员变量
在不同的作用域当中,变量名可以相同的;
在同一个作用域当中,变量名是不能相同的。
数据类型
数据类型的作用是什么?
- 程序当中有很多数据,每一个数据都是有相关类型的,不同数据类型的数据占用空间大小不同。
数据类型的作用是指导JVM在运行程序的时候给该数据分配多大的内存空间
Java中的数据类型包括2种:
- 基本数据类型
- 引用数据类型【后边讲】
- 类
- 接口
- 数组
- …
基本数据类型包括4大类8小种:
第一类:整数型
byte. short. int. long
第二类:浮点型
float, double
第三类::布尔型
boolean
第四类:字符型
char
字符串不属于基本类型,属于”引用数据类型“,字符属于基本数据类型
- 字符串使用双引号 “b”
- 字符使用单引号 ‘a’
八种基本数据类型各自占用空间大小是多少?
基本数据类型 | 占用空间大小【单位:字节】 |
byte | 1 |
short | 2 |
int | 4 |
long | 8 |
float | 4 |
doule | 8 |
boolean | 1 |
char | 2 |
计算机在任何情况下都只能识别二进制【现代计算机底层采用交流电的方式,接通和断开就两种状态,计算机只识别1或0,其他不认识】
什么是二进制?
数据的一种表示形式,十进制表示满10进1原则,二进制表示满2进1原则
1 byte = 8 bit 【1字节 = 8比特位】1个比特位表示一个二进制位
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
1 TB = 1024 * 1024 * 1024 * 1024 * 8 Bit
整数型当中的byte类型,占用1个字节,所以byte类型的数据占用8个比特位,那么byte类型的取值范围?
- 关于java中的数字类型,数字都是有正负之分的,所以在数字的二进制当中有一个二进制位被称为“符号位”并且这个符号位在所有二进制位的最左边,0表示整数,1表示符数
- Byte类型最大值:01111111【10000000(二进制) - 1 = 01111111】
- Byte类型最大值:2的7次方 -1 ,结果是127
- Byte类型的最小值:-128
- Byte类型的取值范围:-128 ~ 127
- Byte类型可以表示256个不同的数字
a=> 97【01100001】
A => 65
0 => 46
a –(按照ASCII解码)à01100001
01100001—(按照ASCII编码)àa
编码和解码时采用同一套字典/对照表,不会出现乱码
当解码和编码的时候采用的不是同一套对照表,会出现乱码问题
Java语言采用的编码方式:
- Java语言源代码采用的是unicode编码方式,所以“标识符”可以用中文
现在在实际开发中,一般使用UTF-8编码方式较多,【统一编码方式】
short和char所表示的种类总数是一样的,只不过char可以表示更大的正整数,因为char没有负数。
关于8种数据类型的默认值:
- 8种数据类型的默认值一切向0看齐
转义字符 \
转义字符出现在特殊字符之前,会将特殊字符转换成普通字符
\n 换行符
\t 制表符
\’ 普通的单引号
\\ 普通的反斜杠
\” 普通的双引号
- Java语言中的“整数型字面值”被默认当作int类型来处理,要让这个“整数型字面值”被当作long类型来处理的话,需要在整数型字面值后面添加l或L,建议使用大写的L
- Java语言当中的整数型字面值有三种表示方式:
- 十进制【缺省默认的方式】
- 八进制【在编写八进制整数型字面值的时候要以0开始】
- 十六进制【在编写十六进制整数型字面值的时候要以0x开始】
- float单精度【4字节】
- double双精度【8字节,精度较高】
- double精度太低,不适合做财务软件
- 基础SE库中准备了精确度更高的类型,是一种引用数据类型,不属于基本数据类型:java.math.BigDecimal
- Java程序中提供了一套庞大的类库,java程序员是基于这套基础的类库进行开发的。
- 在java语言当中,所有浮点型字面值默认被当作double类型来处理,要想该字面值当作float类型来处理,要在字面值后面添加F/f
- 注意:
double和float在计算机内部二进制存储的时候存储的都是近似值
在现实世界当中有些数字是无限循环的,计算机资源是有限的,用有限的资源存储无限的数据只能存储近似值
- 在java语言当中boolean类型只有两个值:true/false,没有其他值。不像c语言当中,0和1可以表示假和真
- 在底层存储的时候boolean类型占用1字节,因为实际存储的时候false底层是0,true底层是1
- 布尔类型在实际开发当中非常重要,经常使用在逻辑运算和条件控制语句当中。
关于基本数据类型之间的互相转换:
- 转换规则
- 8种基本数据类型当中除布尔类型之外剩下的7种类型之间都可以互相转换
- 小容量向大容量转换,称为自动类型转换,容量从大到小排序:
byte < short < int < long < float < double
注意:
- 任何浮点类型不管占用多少个字节,都比整数容量大
- char和short可表示的种类数量相同,但是char可以取更大的正整数
- 多种数据类型混合运算,先转换成容量最大的那种类型再做运算
- byte, short, char混合运算时,各自先转换成int类型再做运算
- 当整数字面值没有超出byte , short , char的取值范围,可以直接赋值给byte , short , char 类型的变量
- 大容量转换成小容量:叫做强制类型转换,需要加强制类型转换符,程序才能编译通过,但是在运行阶段可能会损失精度,所以谨慎使用
-
当整数字面值没有超出byte , short , char的取值范围,可以直接赋值给byte , short , char 类型的变量
-
byte, short, char混合运算时,各自先转换成int类型再做运算
-
多种数据类型混合运算,先转换成容量最大的那种类型再做运算
运算符
+ 求和
- 相减
* 乘积
/ 商
% 求余【取模】
++ 自加1
-- 自减1
注意:
一个表达式当中有多个运算符,运算符有优先级,不确定的加小括号,优先级得到提升。没有必要专门记忆运算符优先级。
优先级:
() ! +(正号) =(负号)
~ ++ --
乘除模除:/ * %
加减:+ -
位运算符:>> <<
关系运算符:& | && ||
- 关系运算符
- > 大于
- >= 大于等于
- < 小于
- <= 小于等于
- == 等于 【= 是赋值运算符,==是关系运算符】
- != 不等于
- 关系运算符的结果一定是布尔类型:true/false
- 关系运算符的运算原理:比较的时候,比较的是两个变量中保存的值之间的大小比较
运算符 | 名称 | 说明 |
& | 逻辑与[并且] | 两边的算子都是true,结果才是true |
| | 逻辑或【或者】 | 两边的算子只要有一个是true,结果就是true |
! | 逻辑非 | 取反,!false = true;!true = false,这是一个单目运算符 |
^ | 逻辑异或 | 两边的算子只要不一样,结果就是true |
&& | 短路与 |
|
|| | 短路或 |
|
- 逻辑运算符要求两边算子都是布尔类型,并且逻辑运算符最终的运算结果也是一个布尔类型
- 短路与和逻辑与最终的运算结果是相同的,只不过短路与存在短路现象
- 短路或和逻辑或最终的运算结果是相同的,只不过短路或存在短路现象
- 什么情况下发生短路现象?
- 什么时候选择使用逻辑与运算符?什么时候选择使用短路与运算符?
字符串连接运算符
- 关于java中的“+”运算符:
- +运算符在java语言当中有两个作用
- 加法运算,求和
- 字符串的连接运算
- 当“+”运算符两边的数据都是数字的话,一定是进行加法运算
- 当“+“运算符两边的数据只要有一个数据是字符串,一定会进行字符串连接运算。并且,连接运算之后的结果还是一个字符串类型。
-
数字 + 数字 à 数字【求和】
-
数字 + “字符串“ à ”字符串“【字符串连接】
- 在一个表达式当中可以出现多个“+“,在没有添加小括号的前提下,遵循自左向右的顺序依次运算
布尔表达式 ? 表达式1 : 表达式2
- 三元运算符的执行原理:
- 当布尔表达式的结果是true的时候,选择表达式1作为整个表达式的结果
- 当布尔表达式的结果是false的时候,选择表达式2作为整个表达式的结果
- 赋值类运算符
- 基本赋值运算符
- =
- 扩展赋值运算符
- +=
- -=
- *=
- /=
- %=
- 基本赋值运算符
- 赋值类运算符优先级:先执行等号右边的表达式,将执行结果赋值给左边的变量。
- 注意以下代码:
(a)Byte i = 10;
I += 5; 等同于:I = (byte)(i+5);
(b)Int k = 10;
K += 5;等同于:k = (int)(k+5);
(c)Long x = 10L;
Int y = 20;
Y += x;等同于:y = (int)(y+x);
重要结论:扩展类的赋值运算符不改变运算结果类型。假设最初这个变量的类型是byte类型,无论怎么进行追加或追减,最终该变量的数据类型还是byte类型。
控制语句
1. 选择结构
a) If, if.. else
i. If
1. 属于选择结构,if语句又被称为分支语句/条件控制语句
a) 语法结构:四种编写方式
i. If(布尔表达式){
Java语句;
…
}
ii. If(布尔表达式){
Java语句;
…
}else{
Java语句;
…
}
iii. If(布尔表达式){
Java语句;
}else if(布尔表达式){
Java语句;
…
}else if(布尔表达式){
Java语句;
…
} else if(布尔表达式){
Java语句;
…
}
else if(布尔表达式){
Java语句;
…
}
else if(布尔表达式){
Java语句;
…
}
iv. If(布尔表达式){
Java语句;
…
}else if(布尔表达式){
Java语句;
…
}else if(布尔表达式){
Java语句;
…
}else{
Java语句;
…
}
b) 对于java中的if语句来说,只要有一个分支执行,真个if语句全部结束
c) 以上的第二种/第四种编写方式都带有else分支,这两种方式可以保证会有分支执行
d) 所有的控制语句都是可以嵌套使用的,只要合理嵌套就行
注意:嵌套使用的时候,代码格式要保证完美
e) If语句的分支中,只有一条java语句的话,大括号可以省略不写
ii. 接收用户键盘输入,从键盘到内存。【输入的过程】
b) Switch
i. Switch语句也属于选择结构,也是分支语句
ii. Switch语句的语法结构:
一个比较完整的switch语句应该这样编写:
Switch(int 或String类型的字面值或变量){
Case int或String类型的字面值或变量:
Java语句;
Java语句;
…
Break;
Case int或String类型的字面值或变量:
Java语句;
Java语句;
…
Break;
Case int或String类型的字面值或变量:
Java语句;
Java语句;
…
Break;
Default:
Java语句;
…
}
iii. Switch语句执行原理:
Switch后面小括号当中的“数据”和case后面的“数据”进行一一匹配,匹配成功的分支执行。按照自上而下的顺序依次匹配。
iv. 匹配成功的分支执行,分支当中最后有“break”语句的话,整个switch语句终止。
v. 匹配成功的分支执行,分支当中最后没有“break”语句的话,直接进入下一个分支执行(不进行匹配)这种现象被称为case穿透现象。【提供break;语句可以避免穿透】
vi. 所有分支都没有匹配成功,当有default的语句话,会执行default分支当中的程序
vii. Switch后面和case后面只能是int或者String类型的数据,不能是探测其他类型。
1. 当然byte, short, char也可以直接写到switch和case后面,因为它们可以进行自动类型转换。Byte, short, char可以自动转换成int类型
2.
viii. Case可以合并:
Switch(i){
Case 1:case 2:case 3:case 10:
System.out.println(“hello”);
}
ix.
2. 循环结构
a) For
i. 循环结构:
在程序当中,总有一些反复的执行的代码。把需要反复执行的代码片段放到“循环体”,再联合计数器,共同控制这段需要反复执行的代码
ii. For循环的语法结构
For(初始化表达式; 布尔表达式; 更新表达式){
//需要重复执行的代码片段【循环体:由java语句构成】
}
iii. For循环的执行过程/原理【非常重要】
1. 初始化表达式、布尔表达式、更新表达式都不是必须的【但两个分号是必须的】
2. 初始化表达式最先执行,并且再整个for循环当中只执行一次
3. 布尔表达式必须是true/false,不能是其他值
4. For的执行过程:
a) 执行初始表达式,并且该表达式只执行一次
b) 判断布尔表达式的结果是true/false
i. 布尔表达式true
执行循环体
执行更新表达式
判断布尔表达式的结果是true/false
执行循环体
执行更新表达式
判断布尔表达式的结果是true/false
……
ii. 布尔表达式false
执行结束
iii.
c)
iv.
b) While
i. While循环的语法结构:
1. While(布尔表达式){
循环体;
}
2.
ii. While循环的执行原理:
1. 先判断bool表达式的结果:
a) True
i. 执行循环体
1. 判断布尔表达式的结果:
a) Ture
i. 执行循环体
ii. 判断布尔表达式的额结果
iii. False:循环结束
iii. While循环的循环次数:
1. 0-N次
2. 注意:while循环的循环体可能一次都不执行
c) Do…while{}
i. Do while循环的语法结构
Do{
循环体;
}while(布尔表达式);
ii. Do while循环的执行原理
iii. Do while循环的执行次数
1 -N次【至少一次】
iv. 使用do while 循环的注意事项:
Do while循环语句最终有个分号别丢了
3. 控制循环语句
a) Break
i. Break是java语句当中的关键字,被翻译为”中断,折断”
ii. Break + “;”可以成为一个单独的完整的java语句:break;
iii. Break语句使用在switch语句当中,用来终止switch的语句执行。
iv. Break语句同样可以使用在循环语句当中,用来终止循环的执行
v. Break终止哪个循环?
vi. Break语句使用在for, while, do while循环语句当中用来跳出循环,终止循环的执行。因为当循环到某个条件的时候,后续的循环没必要执行了,在执行也是耗费资源,所以可以终止循环,这样可以提高程序的执行效率。
vii. 在默认情况下,break语句终止的是离它最近的循环语句,当然也可以指定终止某个循环,需要给循环起名,采用这种语法:break 循环名称
b) Continue
i. Continue表示:继续/go on/下一个
ii. Continue也是一个continue关键字加一个分号构成一个单独完成的java语句,主要出现循环语句当中用来控制循环的执行
iii. Break和continue的区别?
1. Break表示循环不执行了
2. Continue表示终止当前“本次”循环,直接进入下一次循环继续执行
iv. Continue也有这样的语法:
Continue + 循环名称
方法
方法的基础语法
方法怎么定义,语法结构:
[修饰符列表]返回值类型 方法名(形式参数列表){
方法体;
}
对以上的语法结构进行解释说明:
关于修饰符列表
- 可选项,不是必须的
- 目前统一写成public static【以后讲】
- 方法的修饰符列表当中有“static”关键字的话,怎么调用这个方法?
- 类名.方法名(实际参数列表);
返回值类型
- 什么是返回值?
一个方法是可以完成某个特定功能的,这个功能结束后大多数都是需要返回最终执行结果的,执行结果可能是一个具体存在的数据。而这个具体存在的数据就是返回值。
- 返回值类型?
返回值是一个具体存在的数据,数据都是有类型的,此处需要指定的是返回值的具体类型
- 返回值可以指定哪些类型?
Java任意一种类型都可以,包括基本数据类型和所有的引用数据类型。
- 也可能方法结束执行之后不反悔任何数据,java中规定,当一个方法执行结束后不反悔任何数据的话,返回值类型位置必须编写:void关键字
- 返回值类型可以是:
Byte, short, int, float, double, char, String, void, Boolean …
- 返回值类型若不是void,表示这个方法执行结束之后必须返回一个具体的数值。当方法执行结束的时候没有返回任何数据的话编译器报错。
- 返回值:
Return 值;
并且要求“值”的数据必须和方法的返回值类型一致,不然编译器报错。
- 返回值类型是void的时候,在方法体当中不能编写“return 值”这样的语句。
- 只要带有return关键字的语句执行,return语句所在的方法结束。
- 方法名:
- 只要是合法的标识符就行
- 方法名最好见名知意
- 方法名最好是动词
- 方法名首字母要求小写,后面每个单词首字母大写
- 方法体必须由大括号括起来,方法体当中的代码有顺序,遵循自上而下的顺序依次执行。并且方法体由java语句构成,每一个java语句以“;“结尾。
- 形式参数列表:简称形参
- 形参是局部变量
- 形参的个数可以是0 -N 个
- 多个形参之间用逗号隔开
- 形参中起决定性作用的是形参的数据类型,形参的名字就似乎局部变量的名字。
方法怎么调用
- 方法只定义不去调用是不会执行的,只有在调用的时候才会执行。
- 语法规则:《方法的修饰符列表当中有static》
类名.方法名(实参列表):<这是一条java语句,表示调用某个类的某个方法,传递这样的实参>
方法的重复机制overload
方法的本质:
方法就是一段代码片段,并且这段代码片段可以完成某个特定的功能,并且可以被重复的使用。
方法的优点:
代码得到了重复使用
方法定义在类体当中,在一个类当中可以定义多个方法,方法编写的位置没有先后顺序,可以随意
方法体当中不能在定义方法
方法体由java语句构成,方法体中的代码遵守自上而下的顺序依次执行。
方法的调用不一定在main方法当中,可以在其他方法当中。只要是程序可以执行到的位置,都可以取调用其他方法。
方法调用的时候实参和形参要求个数对应相同,数据类型对应相同
类型不同的时候要求能够进行相应的自动类型转换
方法的调用:
方法的修饰符列表当中有static关键字,完整的调用方式是:
类名.方法名(实参列表);
但是,有的时候“类名.”可以省略
M1方法和m2方法在同一个类体当中,“类名.”可以省略使用
建议在1个java源文件当中只定义1个class
方法的返回值类型不是void的时候
返回值类型不是void的时候,要求方法必须百分百的执行“return 值;”这样的语句来完成值的返回,没有这个语句编译器会报错。
一个方法有返回值的时候,当我们调用这个方法的时候,方法返回了一个值,对于调用者来说,这个返回值可以选择接收,也可以选择不接收。
深入return语句
带有return关键字的java语句只要执行,所在的方法执行结束
在同一个作用域当中,return语句下面不能编写任何代码,因为这些代码永远都执行不到,所以编译报错。
在返回值类型是void的方法当中使用“return;”语句
“return;”出现在返回值为void的方法当中主要是为了结束当前的方法
方法在执行过程当中,在JVM中的内存是如何分配的?内存是如何变化的?
方法只定义,不调用,是不会执行的,并且在JVM中也不会给该方法分配“运行所属”的内存空间。只有在调用这个方法的时候,才会动态的给这个方法分配所属的内存空间。
在JVM内存划分上,有这样三块主要的内存空间(除了这三块之外还有其他的内存空间)
方法区内存
堆内存
栈内存
关于栈数据结构
栈:stack,是一种数据结构
数据结构反应的是数据的存储形态
JavaSE当中的集合 使用了大量的数据结构
方法执行的时候,代码片段存在哪里?方法执行的时候执行过程的内存在哪里分配?
- 方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候,将其放到了方法去当中,所以JVM中的三块主要的内存空间中方法区内存最先有数据,存放了代码片段。
- 代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存中分配。【栈内存中分配方法运行的所属内存空间】
方法在调用的瞬间,会给该方法分配独立的内存空间,在栈中分配,此时发生压栈动作,方法执行结束之后,给该方法分配的内存空间全部释放,此时发生弹栈动作。
- 压栈:给方法分配内存
- 弹栈:释放该方法的内存空间
局部变量在栈中存储,局部变量在运行阶段内存在栈中分配。
- 重点:方法调用的时候,在参数传递的时候,实际上传递的是变量中保存的那个值传过去了。
- 不适用overload,程序存在的缺点?
- 方法虽然功能不同,但是功能是相似的,都是求和。功能相似的方法起了不同的名字,这对于程序员来说调用的时候不方便,程序员需要记忆更多的方法才能 完成调用。【不方便】
- 代码不美观
- Overload的优点:
- 程序员调用方法的时候比较方便,虽然调用的是不同的方法,但是就像在使用一个方法一样,不需要记忆更多的方法名。
- 代码美观
- 前提:功能相似的时候,方法名可以相同
- 功能不同的时候,尽可能让方法名不同
什么是递归?
方法自身调用自身
递归是很耗费栈内存的,递归算法可以不用尽量不用。
Java.lang.StackOverflowError
栈内存溢出错误
错误发生无法挽回,只有一个结果,就是JVM停止工作
递归必须有结束条件,没有结束条件一定会发生栈内存溢出错误。
递归即使有了结束条件,即使结束条件是正确的,也可能会发生栈内存溢出错误,因为递归太深了。
注意:递归可以不使用尽量别用
但有些情况下功能的实现必须依靠递归
面向对象【Java语言的核心机制,最重要的内容,Java语言的特色】
- 面向过程:主要关注点是:实现的具体过程,因果关系
- 优点:对于业务逻辑比较简单的程序,可以达到快速开发,前期投入成本较低
- 缺点:采用面向过程的的方式开发很难解决非常复杂的业务逻辑,另外面向过程的方式导致软件元素之间的“耦合度”非常高,只要其中一环出问题,整个系统受到影响,导致最终的软件扩展力差,另外由于没有独立体的概念,所以无法达到组件服用。
- 面向对象:主要关注点是:主要关注对象【独立体】能完成哪些功能
- 优点:耦合度低,扩展力强,更容易解决现实世界到那个中更复杂的业务逻辑,组件复用性强
- 缺点:前期投入成本较高,需要进行独立体的抽取,大量的系统分析和设计
- C语言是纯面向过程的,C++半面向对象,Java纯面向对象
- 现在出现的新的编程语言多数都是面向对象的,人在认识现实世界的时候以面向对象的方式
- 面向对象更符合人的思维方式
- 封装
- 继承
- 多态
- 所有面向对象的编程语言都有这三大特征
- 采用面向对象的方式开发一个软件,生命周期当中:【整个生命周期中贯穿使用OO面向对象方式】
- 面向对象的分析:OOA
- 面向对象的设计:OOD
- 面向对象的编程:OOP
类和对象的概念
- 什么是类:
- 类在现实世界中不存在的,是一个模板,是一个概念,是人类大脑思考抽象的结果
- 类代表了一类事物
- 在现实世界当中,对象A与对象B之间具有共同特征,进行抽象总结出一个模板,这个模板被称为类
- 什么是对象:
- 对象是实际存在的个体,现实世界当中实际存在
- 描述一下整个软件开发的过程:
- 程序员先观察现实世界,从现实世界当中寻找对象
- 寻找了N多个对象后,发现所有的对象都有共同特征
- 程序员在大脑中形成了一个模板【类】
- Java程序员可以通过Java代码来表一个类
- Java程序中有了类的定义
- 然后通过类就可以创建对象
- 有了对象之后,可以让对象直接协作起来形成一个系统。
- 类--【实例化】à对象
- 对象又被称为实例/instance
- 对象—[抽象]à类
- 重点:
类描述的是对象的共同特征
共同特征例如:身高特征
这个身高特征在访问的时候,必须先创建对象,通过对象去访问这个特征,因为这个特征具体到某个对象上之后,值不同。有的对象身高1.80,有的对象身高2.80
一个类主要描述什么信息呢?
一个类主要描述的是状态 + 动作。
状态信息:名字/身高/性别/年龄
动作信息:吃/唱歌/跳舞/学习
状态à一个类的属性
动作à一个类的方法
类{
属性:描述对象的状态信息
方法:描述对象的动作信息
}
注意:
状态和动作当具体到某个对象上之后,发现最终的结果可能不一样。
对象和对象之间有共同特征,但是具体到对象之后有数据的差异。
类的定义
语法结构:
[修饰符列表] class 类名 {
属性;
方法;
}
学生类:描述所有学生对象的共同特征:
学生对象有哪些状态信息:
- 学号【int】
- 名字【String】
- 性别【boolean】
- 年龄【int】【年龄是一个属性,年龄是一个数据,是数据就应该由数据类型】
- 住址【String】
- ……
学生对象有哪些动作信息:
- 吃饭
- 睡觉
- 学习
- 玩
- 唱歌
- 跳舞
- ……
重点:属性通常是采用一个变量的形式来完成定义的。
对象的创建和使用
1. public class Student{
2. //类体 = 属性 + 方法
3. //属性【存储数据采用变量的方式】
4. //由于变量定义在类体当中,方法体之外,这种变量称为成员变量
5.
6. //所有学生都有学号信息
7. //但是每个学生的学号都是不同的
8. //所以要访问这个学号必须先创建对象,通过对象去访问学号信息
9. //学号信息不能直接通过“类”去访问,所以这种成员变量又被叫做:实例变量
10. //对象又被称为实例,实例变量又被称为对象变量。[对象级别的变量]
11. //不创建对象,这个no变量的内存空间是不存在的,只有创建了对象,这个no变量内存空间才会创建。
12. int no;
13. int age;
14. boolean sex;
15. String name;
16. String addr;
17. }
18.
19. //成员变量没有手动赋值的话,系统赋默认值
20. //默认值
21. /**
22. * 数据类型 默认值
23. * -------------------------------------
24. * byte, short, int , long 0
25. * float, double 0.0
26. * boolean false
27. * char \u0000
28. * 引用数据类型 null 空值
29. */
1. public class OOTest01{
2. public static void main(String[] args){
3.
4. //int是基本数据类型
5. //i是变量名
6. //10是一个int类型的字面值
7. int i = 10;
8. //通过一个类可以实例化N个对象
9. //实例话对象的语法:new 类名()
10. //new运算符的作用是创建对象,在JVM堆内存当中开辟新的内存空间
11. //方法区内存:在类加载的时候,class字节码代码片段被加载到该内存空间中
12. //栈内存(局部变量):方法代码片段执行的时候,会给该方法分配内存空间,在栈中压栈。
13. //堆内存:new的对象在堆内存中存储
14.
15. //Student是一个引用数据类型
16. //s是一个变量名
17. //new Student()是一个学生对象
18. //s;是一个局部变量[在栈内存中存储]
19. Student s = new Student();
20.
21. //什么是对象?new运算符创建在堆内存中开辟的内存空间称为对象
22. //什么是引用?引用是一个变量,只不过这个变量中保存了另一个java对象的内存地址
23. //Java语言当中,程序员不能直接操作堆内存,java中没有指针,不像C语言
24. //Java语言当中,程序员只能通过“引用”去访问堆内存当中对象内部的实例变量
25.
26. //访问实例变量的语法格式:
27. //读取数据:引用.变量名
28. //修改数据:引用.变量名 = 值;
29. /*
30. int stuNo = s.no;
31. String stuName = s.name;
32. int stuAge = s.age;
33. boolean stuSex = s.sex;
34. String stuAddr = s.addr;
35.
36. System.out.println("学号:" + stuNo);
37. System.out.println("姓名:" + stuName);
38. System.out.println("年龄:" + stuAge);
39. System.out.println("性别:" + stuSex);
40. System.out.println("地址:" + stuAddr);
41. */
42. System.out.println("学号:" + s.no); //0
43. System.out.println("姓名:" + s.name); //null
44. System.out.println("年龄:" + s.age); //0
45. System.out.println("性别:" + s.sex); //false
46. System.out.println("地址:" + s.addr); //null
47.
48. s.no = 10;
49. s.name = "Jack";
50. s.age = 20;
51. s.sex = true;
52. s.addr = "北京";
53.
54. System.out.println("学号:" + s.no); //10
55. System.out.println("姓名:" + s.name); //Jack
56. System.out.println("年龄:" + s.age); //20
57. System.out.println("性别:" + s.sex); //true
58. System.out.println("地址:" + s.addr); //北京
59.
60. //再通过类实例化一个全新的对象
61. //stu是一个引用
62. //stu同时也是一个局部变量
63. //Student是变量的数据类型
64. Student stu = new Student();
65.
66. System.out.println(stu.no);
67. System.out.println(stu.name);
68. System.out.println(stu.age);
69. System.out.println(stu.sex);
70. System.out.println(stu.addr);
71.
72. //编译报错:no这个实例变量不能直接采用“类名”的方式访问
73. //因为no是实例变量,对象级别的变量,变量存储在java对象的内部,必须先有对象
74. //通过对象才能访问no这个实例变量,不能直接通过类名访问
75. //System.out.println(Student.no);
76.
77. }
78. }
79.
80. /**
81. * 局部变量再栈内存中存储
82. * 成员变量中的实例变量在堆内存的java对象内部存储
83. *
84. * 实例变量是一个对象一份,100个对象有100份
85. */
1. public class Address{
2. //城市
3. String city;
4. //街道
5. String street;
6. //邮编
7. String zipCode;
8.
9. }
1. public class User{
2.
3. //用户编号
4. int no;
5. //用户名
6. String name;
7. //家庭住址
8. Address addr;
9. }
1. public class OOTest{
2. public static void main(String[] args){
3. User u = new User();
4.
5. System.out.println(u.no); //0
6. System.out.println(u.name); //null
7. System.out.println(u.addr); //null
8.
9. //修改User对象内部实例变量
10. u.no = 110;
11. u.name = "Jack";//"Jack"是一个Java对象,属于String对象
12. u.addr = new Address();
13.
14. u.addr.city = "北京";
15. u.addr.street = "朝阳";
16. u.addr.zipCode = "11111111111111";
17.
18. //在main方法当中目前只能看到一个引用“u”
19. //一切都是只能通过u来进行访问
20. System.out.println(u.name + "居住的城市为:" + u.addr.city);
21. System.out.println(u.name + "居住的街道为:" + u.addr.street);
22. System.out.println(u.name + "邮编为:" + u.addr.zipCode);
23.
24.
25.
26. }
27. }
28. /**------------输出结果-------------
29. * 0
30. * null
31. * null
32. * Jack居住的城市为:北京
33. * Jack居住的街道为:朝阳
34. * Jack邮编为:11111111111111
35. */
1. public class OOTest01{
2. public static void main(String[] args){
3. User u = new User();
4. //u.addr = new Address();
5.
6. Address a = new Address();
7. u.addr = a;
8.
9. System.out.println(u.addr.city);
10.
11. a.city = "天津";
12.
13. System.out.println(u.addr.city);
14. }
15. }
16. /**-----------输出结果-------------
17. * null
18. * 天津
19. */
内存
JVM(Java虚拟机)主要包括三块内存空间:栈内存,堆内存,方法区内存
堆内存和方法区内存各有一个;一个线程一个栈内存。
方法在调用的时候,该方法所需要的内存空间在栈内存中分配,称为压栈;方法执行结束的时候,该方法所属的内存空间释放,称为弹栈
栈中主要存储的是方法体当中的局部变量
方法的代码片段以及整个类的代码片段都被存储到方法区内存中,在类加载的时候这些代码片段会载入
在程序执行过程中,使用new运算符创建的java对象,存储在堆内存中,对象内部有实例变量,所以实例变量存储在堆内存中。
变量分类:
- 局部变量(方法体中声明)
- 成员变量(方法体外声明)
- 实例变量(前边修饰符没有static)
- 静态变量(前边修饰符中有static)
静态变量存储在方法区内存中
三块内存当中变化最频繁的是栈内存,最先有数据的是方法区内存,垃圾回收器主要针对的是堆内存
垃圾回收器【自动垃圾回收机制,GC机制】什么时候会考虑将某个Java对象的内存回收呢?
当堆内存当中的java对象成为垃圾数据的时候,会被垃圾回收器回收。
什么时候内存中的java对象会变成垃圾呢?
-
没有更多的引用指向它的时候
-
这个对象无法访问,因为访问对象只能通过引用的方式访问
空指针异常
1. public class Customer{
2. int id;
3. }
1. public class OOTest{
2. public static void main(String[] args){
3.
4. Customer c = new Customer();
5. System.out.println(c.id);
6.
7. //以下程序编译可以通过,因为符合语法
8. //运行出现空指针异常
9. //空引用访问“实例”相关的数据一定会出现空指针异常
10. //java.lang.NullPointerTxception
11. c = null;
12. System.out.println(c.id);
13. }
14. }
15.
16. //实例相关的数据表示,这个数据访问的时候必须有对象的参与。这种数据就是实例相关的数据。
17.
18. /**-----------------运行结果--------------------
19. * PS D:\study\java\javaworkspace\Customer> javac OOTest.java
20. * PS D:\study\java\javaworkspace\Customer> java OOTest
21. * 0
22. * Exception in thread "main" java.lang.NullPointerException
23. * at OOTest.main(OOTest.java:8)
24. */
定义类的语法:
[修饰符列表] class 类名{
属性;
方法;
}
属性通常采用变量来表示,既然是变量那么变量肯定有数据类型【数据类型包括:基本数据类型 + 引用数据类型】
属性对应的是状态信息
Eclipse快捷键
Alt + / 自动补全
Ctrl + Shift + F文本格式化
封装
1. 为什么要封装?封装的好处?
a) 封装之后,对于那个事物来说,看不到这个事物复杂的那一面,只能看到该事物简单的那一面。复杂性封装,对外提供简单的操作入口。照相机就是一个很好的封装案例,照相机的实现原理非常复杂,但是对于使用照相机的人来说操作起来非常方便。
b) 封装之后才会形成真正的“对象”,真正的“独立体”
c) 封装就意味着以后的程序可以重复使用,并且这个事物应该适应性比较强,在任何场合都可以使用
d) 封装之后,对于事物本身,提高了安全性。【安全级别高】
2. 封装的步骤:
a) 所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。
b) 对外提供简单的操作入口,也就是说以后外部程序想要访问age属性,必须通过这些简单的入口进行访问。
i. 对外提供两个公开的方法,分别是set方法和get方法
1. 想修改属性,调用set方法
2. 想读取属性,调用get方法
c) Set方法的命名规范:
Public void set+属性名首字母大写(形参){
}
d) Get方法命名规范:
Public 返回值类型 get+属性名首字母大写(形参){
}
e)
访问一个属性的访问形式:
像读取这个属性的值,读取get
想修改这个属性的值,修改set
Setter and getter方法没有static 关键字
有static关键字修饰方法怎么调用:类名.方法名(实参);
没有static关键字修饰的方法怎么调用:引用.方法名(实参);
3. 构造方法
a) 构造方法又被称为构造函数/构造器/Constructor
b) 构造方法语法结构:
[修饰符列表] 构造方法名 (形参列表) {
构造方法体;
}
c) 普通方法的语法结构:
[修饰符列表] 返回值类型 方法名 (形参列表) {
方法体;
}
d) 对于构造方法来说,“返回值类型“不需要指定,并且也不能写void,只要写上void,那么这个方法就变成了普通方法
e) 对于构造方法来说,构造方法的方法名必须和类名保持一致
f) 构造方法的作用:
构造方法存在的意义是:通过构造方法的调用,可以创建对象。
g) 构造方法应该怎么调用:
- 普通方法是这样调用的:
方法修饰符中有static的时候:类名.方法名(实参列表)
没有static的时候:引用.方法名(实参列表)
- New 构造方法名(实参列表)
h) 构造方法调用执行之后有返回值吗?
每一个构造方法执行结束之后都有返回值,但是“return 值;”这样的语句不需要写。构造方法结束的时候java程序自动返回值。
并且返回值类型是构造方法所在类的类型。
i) 当一个类中没有定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个构造方法被称为缺省构造器。
j) 当一个类显示的将构造方法定义出来了,那么系统则不再默认为这个类提供缺省构造器
k) 构造方法支持重载机制,在一个类当中编写多个构造方法,这多个构造方法显然已经构成方法重载机制。
l) 构造方法的作用
i. 创建对象
ii. 创建对象的同时。初始化实例变量的内存空间。【给实例变量赋值】
iii. 成员变量之实例变量,属于对象级别的变量,这种变量必须先有对象才能有实例变量。
iv. 实例变量没有手动赋值的时候,系统默认赋值。那么这个系统默认赋值时在什么时候完成的呢?是在类加载的时候吗?
不是,因为类加载的时候只加载了代码片段,还没来得及创建对象。所以此时实例变量并没有初始化。
实际上,实例变量的内存空间是在构造方法执行过程当中完成开辟的,完成初始化的。
系统在默认赋值的时候,也是在构造方法执行过程当中完成的赋值。
实例变量是存储在堆内存Java对象的内部。
- 查看访问的是哪个属性,哪个方法?
按ctrl键,鼠标移动到查看的元素上,出现下划线的时候单击
- 在一个类当中元素过多,想快速查看,在当前类中使用ctrl + o快捷键,然后输入要查找的元素名称,该名称不一定输入全名称。
对象和引用
1. 对象和引用的概念
a) 对象:目前在使用new运算符在堆内存中开辟的内存空间称为对象。
b) 引用:是一个变量,不一定是局部变量,还可能是成员变量,引用保存了内存地址,指向了堆内存当中的对象。
c) 所有访问实例相关的数据,都需要通过”引用.”的方式访问,因为只有通过引用才能找到对象。
d) 只有一个空的引用,访问对象的实例和相关的数据会出现空指针异常。
2. 参数的传递
主要研究和学习的是方法在调用的时候,涉及到参数传递的问题,到底是怎么传递数据的呢?
a) 方法调用时涉及到的参数传递,实际上传递的是变量中保存的具体值
b) 最终结论:
方法调用的时候涉及到参数传递的问题,传递的时候,java只遵循一种语法机制,就是将变量中保存的值传递过去了,只不过有的时候这个值是一个字面值,有的时候这个值时另一个java对象的内存地址
this关键字
- This是一个关键字,翻译为:这个
- This是一个引用,this是一个变量,this变量中保存了内存地址指向了自身,this存储在JVM堆内存java对象内部
- 每一个对象都有this
- This可以出现在实例方法当中,this指向当前正在执行这个动作的对象。
- This不能在带有static的方法中使用
重点:没有static关键字的方法被称为“实例方法”,通过“引用.”访问
重点:没有static关键字的变量被称为:实例变量
注意:但一个行为执行的过程当中是需要对象参与的,那么这个方法一定要定义为“实例方法”,不要带static关键字
最终结论:
在带有static的方法当中不能“直接”访问实例变量和实例方法
因为实例变量和实例方法都需要对象的存在
而static的方法当中是没有this的,也就是说当前对象是不存在的。
自然也是无法访问当前对象的实例变量和实例方法
This什么时候不能省略
- 用来区分局部变量和实例变量的时候
This可以用在哪里
- 可以用在实例方法当中,代表当前对象【语法格式:this.】
- 可以使用在构造方法当中,通过当前的构造方法调用其他的构造方法【语法格式:this(实参);】
重点:this()这种语法只能出现在构造方法的第一行。
带有static的方法,其实既可以采用类名的方式访问,也可以采用引用的方式访问
但是即使采用引用的方式访问,实际上执行的时候和引用指向的对象无关。
带有static的方法建议采用类名.方法的方式访问。
Static关键字
静态变量,静态变量在类加载的时候初始化,不需要创建对象,内存就开辟了
静态变量存储在方法区的内存中
什么时候成员变量声明为实例变量?
- 所有对象都有这个属性,但是这个属性的值会随着对象的变化而变化【不同对象的这个属性具体的值不同】
什么时候成员变量声明为静态变量?
- 所有对象都有这个属性,并且所有对象的这个属性的值是一样的,建议定义为静态变量,节省内存的开销。
静态变量在类加载的时候初始化,内存在方法区中开辟,访问的时候不需要创建对象,直接使用“类名.静态变量名”的方式访问。
1. package com.OOProjectnode;
2.
3. public class Chinese {
4. private String id;
5. private String name;
6. private static String Country = "中国";
7.
8. public String getId() {
9. return id;
10. }
11.
12. public void setId(String id) {
13. this.id = id;
14. }
15.
16. public String getName() {
17. return name;
18. }
19.
20. public void setName(String name) {
21. this.name = name;
22. }
23.
24. public static String getCountry() {
25. return Country;
26. }
27.
28. public static void setCountry(String country) {
29. Country = country;
30. }
31.
32. public Chinese(String id, String name) {
33. this.id = id;
34. this.name = name;
35. }
36.
37. public Chinese() {
38. this.id = null;
39. this.name = null;
40. }
41. }
1. package com.OOProjectnode;
2.
3. public class ChineseTest {
4.
5. public static void main(String[] args){
6. Chinese zhangsan = new Chinese("1", "张三");
7. System.out.println(zhangsan.getId()+ ","+zhangsan.getName()+","+Chinese.getCountry());
8.
9. Chinese lisi = new Chinese("2", "李四");
10. System.out.println(lisi.getId()+ ","+lisi.getName()+","+Chinese.getCountry());
11.
12. }
13. }
Static英语单词翻译为静态的
Static修饰的方法是静态方法
Static修饰的变量是静态变量
所有static修饰的元素都称为是静态的,都可以使用类名.的方式访问(也可以使用引用.的方式访问,但不建议)
Static修饰的所有元素都是类级别的特征,和具体的对象无关
可以使用static关键字来定义静态代码块:
语法格式:
static{
Java语句;
}
静态代码块在类加载时执行,并且只执行一次
静态代码块在一个类中可以编写多个,并且遵循自上而下的顺序依次执行
静态代码块的作用是什么?怎么用?用在哪?什么时候用?
- 这当然和具体的需求有关,例如项目中要求在类加载的时刻/时机执行代码完成日志记录。那么这段记录日志的代码就可以编写到静态代码块当中,完成日志记录
- 静态代码块是java为程序员准备一个特殊的时刻,这个特殊的时刻被称为类加载时刻,若希望在此刻执行一段特殊的程序,这段程序可以直接放到静态代码块当中。
通常在静态代码块当中完成预备工作,先完成数据的准备工作,例如:初始化连接池。解析XML配置文件……
1. package com.selflearning.statictest010;
2.
3. /**
4. * 可以使用static关键字来定义静态代码块:
5. * 1.语法格式:
6. * static{
7. * java语句;
8. * }
9. *
10. * 2.静态代码块在类加时执行,并且只执行一次
11. * 3.
12. */
13. public class StaticTest010 {
14.
15. static {
16. System.out.println("类加载-->1");
17. }
18. static {
19. System.out.println("类加载-->2");
20. }
21. static {
22. System.out.println("类加载-->3");
23. }
24.
25. public static void main(String[] args){
26. System.out.println("main begin");
27. }
28. }
实例语句块/代码块【了解内容,使用的非常少】
- 实例代码块可以缩写多个,也是遵循自上而下的顺序依次执行
- 实例代码块在构造方法执行之前执行,构造方法执行一次,实例代码块对应执行一次
- 实例代码块也是java语言程序员必备的一个特殊的时机,这个特殊的时机被称为:对象初始化时机
1. package com.selflearning.statictest010;
2.
3. public class StaticTest011 {
4.
5. //构造函数
6. public StaticTest011(){
7. System.out.println("StaticTest011的缺省构造方法");
8. }
9.
10. //实例代码块
11. {
12. System.out.println(1);
13. }
14.
15. //实例代码块
16. {
17. System.out.println(2);
18. }
19.
20. //实例代码块
21. {
22. System.out.println(3);
23. }
24.
25. public static void main(String[] args){
26. System.out.println("main begin");
27. new StaticTest011();
28. }
29. }
30. /*-----------------运行结果-----------------
31. main begin
32. 1
33. 2
34. 3
35. StaticTest011的缺省构造方法
36. * */
方法什么时候定义为静态的?
- 方法描述的是动作,当所有对象执行这个动作的时候,最终产生影响的是一样的,那么这个动作已经不再属于某个对象动作了,可以将这个动作提升为类级别的动作,模板级别的动作。
- 静态方法中无法直接访问实例变量和实例方法
- 大多数方法都定义为实例方法,一般一个行为或者一个动作在发生的时候,都需要对象的参与。但是也有例外,例如:大多数“工具类”中的方法都是静态方法,因为工具类就是方便编程的,为了方便方法的调用,自然不需要new对象是最好的。
继承
- 继承是面向对象三大特征之一【封装,继承,多态】
- 继承基本的作用:
- 代码复用
- 方法的覆盖
- 多态机制
- 继承的语法格式:
[修饰符列表] class 类名 extends 父类名{
类体 = 属性 + 方法
}
- Java语言当中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类,在C++中支持多继承。
- 关于继承的一些术语:
- B类继承A类,其中:
- A类称为:父类,基类,超类,superclass
- B类称为:子类,派生类,subclass
- 在java语言当中,子类继承父类,都继承哪些数据?
- 私有的不支持继承
- 构造方法不支持继承
- 其他数据都可以被继承
- 虽然java语言当中只支持单继承,但是一个类也可以间接继承其他类,例如:
C extends B{}
B extends A{}
A extends T{}
C类直接继承B类,但是C类间接继承T、A类
- Java语言中假设一个类没有显示的继承任何类,该类默认继承JavaSE库当中提供的java.lang.Object类
Java语言中任何一个类中都有Object类的特征
- 快捷键:
- Idea中查找类型: Ctrl + Shift + Alt + N
- Eclipse查找类型: Ctrl + Shift + T
1. package com.selflearning.c04_inherit;
2.
3. public class Account {
4. private String actno;
5. private double balance;
6.
7. public String getActno() {
8. return actno;
9. }
10.
11. public void setActno(String actno) {
12. this.actno = actno;
13. }
14.
15. public double getBalance() {
16. return balance;
17. }
18.
19. public void setBalance(double balance) {
20. this.balance = balance;
21. }
22.
23. public Account(String actno, double balance) {
24. this.actno = actno;
25. this.balance = balance;
26. }
27.
28. public Account() {
29. }
30. }
1. package com.selflearning.c04_inherit;
2.
3. //信用账户
4. public class CreditAccount extends Account{
5.
6. private double credit;
7.
8. public CreditAccount(){
9. super();
10. }
11.
12. public double getCredit() {
13. return credit;
14. }
15.
16. public void setCredit(double credit) {
17. this.credit = credit;
18. }
19. }
1. package com.selflearning.c04_inherit;
2.
3. public class ExtednsTest {
4. public static void main(String[] args) {
5. ExtednsTest et = new ExtednsTest();
6. String s = et.toString(); //这里编译通过了。这说明可以调用toString方法,
7. // ExetendsTest类中有toString方法,从Object类中继承过来的。
8. System.out.println(s); //com.selflearning.c04_inherit.ExtednsTest@10f87f48
9.
10. CreditAccount act = new CreditAccount();
11. act.setActno("act-001");
12. act.setBalance(-1000.0);
13. act.setCredit(0.99);
14.
15. System.out.println(act.getCredit() + " " + act.getBalance() + " " + act.getActno());
16. }
17. }
1. package com.selflearning.c04_inherit;
2.
3. public class ExtendsTest02 {
4. public static void main(String[] args) {
5. C c = new C();
6. c.doSome(); //这里调用的doSome方法是从B类中继承过来的doSome方法
7.
8. }
9. }
10.
11. class A{
12. public void doSome(){
13. System.out.println("do some!");
14. }
15. }
16.
17. class B extends A{
18.
19. }
20.
21. class C extends B{
22.
23. }
关于Java语言当中方法的覆盖(Override【官方的】/Overwrite)
- 方法的覆盖又被称为方法重写
- 什么时候使用方法重写?
- 当父类中的方法已经无法满足当前子类的业务需求,子类有必要将父类中继承过来的方法进行重新编写,这个重新编写的过程称为方法重写/方法覆盖。
- 什么条件满足之后方法发生重写?
- 方法重写发生在具有继承关系的父子类之间
- 方法重写的时候,方法名相同,返回值类型相同,形参列表相同
- 方法重写的时候,访问权限不能更低,可以更高
- 方法重写的时候,抛出异常不能更多,可以更少
- 建议方法重写的时候尽量复制粘贴,不要编写,容易出错,导致没有产生覆盖。
- 注意:
- 私有方法不能继承,所以不能覆盖
- 构造方法不能继承,所以不能覆盖
- 静态方法不存在覆盖
- 覆盖只针对方法,不谈属性
1. package com.selflearning.C05_methodCoverage;
2.
3. public class Animal {
4.
5. public void move(){
6. System.out.println("动物在移动");
7. }
8. }
1. package com.selflearning.C05_methodCoverage;
2.
3. public class Cat extends Animal{
4. public void move(){
5. System.out.println("猫在走猫步");
6. }
7. }
1. package com.selflearning.C05_methodCoverage;
2.
3. public class Bird extends Animal {
4. public void move(){
5. System.out.println("鸟儿在飞翔");
6. }
7. }
1. package com.selflearning.C05_methodCoverage;
2.
3. public class YingWu extends Bird{
4.
5. //这里的move()方法,覆盖的是Bird当中的move()方法
6. @Override
7. public void move() {
8. System.out.println("鹦鹉飞不起来");
9. }
10. }
1. package com.selflearning.C05_methodCoverage;
2.
3. /*
4. * 回顾java语言当中方法的重载:
5. * 1.方法重载又称为Overload
6. * 2.方法重载什么时候使用?
7. * 当在同一个类当中,方法完成的功能是相似的,建议方法名相同,这样方便程序员的编程,就像在调用一个方法似的,代码美观
8. * 3.什么条件满足之后构成方法重载?
9. * - 在同一个类当中
10. * - 方法名相同
11. * - 参数列表不同:类型/顺序/个数
12. * 4.方法重载和什么无关?
13. * - 和方法的返回值类型无关
14. * - 和方法的修饰符列表无关
15. * */
16.
17. public class OverrideTest01 {
18. public static void main(String[] args) {
19. Animal a = new Animal();
20. a.move();
21.
22. Cat c = new Cat();
23. c.move();
24.
25. Bird b = new Bird();
26. b.move();
27.
28. YingWu y = new YingWu();
29. y.move();
30. }
31. }
32.
33. /**
34. * ----------------------运行结果----------------------
35. * 动物在移动
36. * 猫在走猫步
37. * 鸟儿在飞翔
38. * 鹦鹉飞不起来
39. * */
多态
- Animal、Cat、Bird三个类之间的关系:
- Cat继承Animal
- Bird继承Animal
- Cat和Bird之间没有任何继承关系
- 面向对象三大特征:封装、继承、多态
- 关于多态中涉及到的几个概念:
- 向上转型(upcasting)
- 子类型 à 父类型
- 又被称为:自动类型转换
- 向下转型(downcasting)
- 父类型 à 子类型
- 又被称为:强制类型转换【需要加强制类型转换符】
- 不论是向上转型还是向下转型,两种类型之间必须要有继承关系。没有继承关系程序是无法编译通过的
- 向上转型(upcasting)
1. package com.selflearning.C06_Polymorphism;
2.
3. public class Animal {
4.
5. public void move(){
6. System.out.println("动物在移动");
7. }
8. }
1. package com.selflearning.C06_Polymorphism;
2.
3. public class Bird extends Animal {
4.
5. //重写从父类中继承过来的方法
6. public void move(){
7. System.out.println("鸟儿在飞翔");
8. }
9. }
1. package com.selflearning.C06_Polymorphism;
2.
3. public class Cat extends Animal {
4.
5. //重写父类中继承过来的方法
6. public void move(){
7. System.out.println("猫在走猫步");
8. }
9.
10. //不是从父类继承过来的方法
11. //这个方法是子类对象特有的行为【不是所有动物都能抓老鼠】
12. public void catchMouse(){
13. System.out.println("猫抓老鼠!");
14. }
15. }
1. package com.selflearning.C06_Polymorphism;
2.
3. public class Test01 {
4.
5. public static void main(String[] args) {
6.
7. Animal a1 = new Animal();
8. a1.move();
9.
10. Cat c1 = new Cat();
11. c1.catchMouse();
12. c1.move();
13.
14. Bird b1 = new Bird();
15. b1.move();
16.
17. //使用多态语法机制
18.
19. /**
20. * 1. Animal和Cat之间存在继承关系,Animal是父类,Cat是子类
21. *
22. * 2.new Cat()创建的对象的类型是Cat,a2这个引用的数据类型是Animal,可见它们进行了类型转换
23. * 子类型转换成父类型,称为向上转型/upcasting,或者称为自动类型转换
24. *
25. * 3.java中允许这种语法:父类型引用指向子类型对象
26. * */
27. Animal a2 = new Cat();
28.
29. /**
30. * 1.程序永远都分为编译阶段和运行阶段
31. *
32. * 2.先分析编译阶段,在分析运行阶段,编译无法通过,根本是无法运行的
33. *
34. * 3.编译阶段编译器检查a2这个引用的数据类型是Animal,
35. * 由于Animal.class字节码当中有move()方法,所以编译通过了。
36. * 这个过程我们称为静态绑定,编译阶段绑定。只有静态绑定成功之后才有后续运行。
37. *
38. * 4.在程序运行阶段,JVM堆内存当中真实创建的对象是Cat对象,
39. * 那么以下程序在运行阶段一定会调用Cat对象的move()方法,
40. * 此时发生了程序的动态绑定,运行阶段绑定。
41. *
42. * 5.无论是Cat类有没有重写move方法,运行阶段一定调用的是Cat对象的move方法,因为底层真实对象就是Cat对象
43. *
44. * 6.父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的形态/状态
45. * 这种机制可以成为一种多态语法机制。
46. * */
47. a2.move(); //猫在走猫步
48.
49. /**
50. * 以下程序为什么不能调用?
51. * 因为编译阶段编译器检查到a2的类型是Animal类型,
52. * 从Animal.class字节码文件当中查找catchMouse()方法,
53. * 最终没有找到该方法,导致静态绑定失败,没有绑定成功
54. * 也就是说编译失败了,无法运行。
55. * */
56. //a2.catchMouse();
57.
58. /**
59. *
60. * */
61. }
62. }
63. /* ----------------- 运行结果 -----------------
64. 动物在移动
65. 猫抓老鼠!
66. 猫在走猫步
67. 鸟儿在飞翔
68. 猫在走猫步
69. * ----------------- 运行结果 -----------------*/
多态在实际开发中的作用
- 降低程序的耦合度,提高程序的扩展力
- 能使用多态则尽量使用多态
- 父类型引用指向子类型对象
核心:面向抽象编程,尽量不要面向具体编程
1. package com.selflearning.C06_Polymorphism.test02;
2.
3. /**
4. * 1.分析:主人喂养宠物这个场景要实现需要进行类型的抽象:
5. * - 主人【类】
6. * - 主人可以喂养宠物,所以主人有喂养的动作
7. * - 宠物【类】
8. * - 宠物可以吃东西,所以宠物有吃东西的动作
9. *
10. * 2.定义好类,然后将类实例化为对象,给一个环境驱使以下,让各个对象之间协作起来形成一个系统
11. */
12.
13. public class Test01 {
14. public static void main(String[] args) {
15.
16. //创建主人对象
17. Master zhangsan = new Master();
18. /*
19. //创建猫对象
20. Cat tom = new Cat();
21. //主人喂养猫
22. zhangsan.feed(tom);
23.
24. Dog erHa = new Dog();
25. zhangsan.feed(erHa);
26.
27. */
28. zhangsan.feed(new Cat());
29. zhangsan.feed(new Dog());
30. Snake mangShe = new Snake();
31. zhangsan.feed(mangShe);
32.
33. }
34. }
35. /* ------------------- 运行结果 -------------------
36. 小猫正在吃鱼!
37. 小狗正在啃骨头!
38. 蛇吞象!
39. ------------------- 运行结果 ------------------- */
1. package com.selflearning.C06_Polymorphism.test02;
2.
3. //这种方式没有使用java语言当中的多态机制
4. // 存在缺点:Master的扩展力差,因为只要加一个新的宠物,Master类就需要添加新的方法。
5. /*
6. public class Master {
7.
8. public void feed(Cat c){
9. c.eat();
10. }
11.
12. public void feed(Dog d){
13. d.eat();
14. }
15. }
16. */
17.
18. //降低程序的耦合度【解耦合】,提高程序的扩展力【软件开发的一个很重要的目标】
19. public class Master{
20.
21. //Master著人类面向的是一个抽象的Pet,不再面向具体的宠物
22. //提倡:面向抽象编程,不要面向具体编程
23. //面向抽象编程的好处:耦合度低,扩展力强
24. public void feed(Pet pet){
25. pet.eat();
26. }
27.
28. }
1. package com.selflearning.C06_Polymorphism.test02;
2.
3. public class Pet {
4. public void eat(){}
5. }
1. package com.selflearning.C06_Polymorphism.test02;
2.
3. public class Cat extends Pet {
4. public void eat(){
5. System.out.println("小猫正在吃鱼!");
6. }
7. }
1. package com.selflearning.C06_Polymorphism.test02;
2.
3. public class Dog extends Pet {
4. public void eat(){
5. System.out.println("小狗正在啃骨头!");
6. }
7. }
1. package com.selflearning.C06_Polymorphism.test02;
2.
3. public class Snake extends Pet {
4. public void eat(){
5. System.out.println("蛇吞象!");
6. }
7. }
Final关键字
- final是一个关键字,表示最终的,不可变的
- final修饰的类无法被继承
- final修饰的方法无法被覆盖
- final修饰的变量一旦赋值之后,不可重新赋值
- final修饰的实例变量
- 必须手动赋值,不能采用系统默认值
- 一般和static联合使用,被称为常量
- final修饰的引用
- 一旦指向某个对象之后,不能再指向其他对象,那么被指向的对象无法被垃圾回收器回收
- 虽然指向某个对象之后不能指向其他对象,但是所指向的对象内部的内存是可以修改的
- eclipse如何链接源码
- 打开某个class字节码文件,当没有看到源码的时候
- 点击Attached Source:
- Workspace..【源码在当前的工作区中】
- External File..【源码在某个压缩包当中】
- External Folder..【源码在某个目录当中】
- 打开某个class字节码文件,当没有看到源码的时候
- idea如何链接源码
- 对于以后学习的类库,一般都是包括三个部分:
- 源码【可以看源码来理解程序】
- 字节码【程序开发的过程中使用的就是这部分】
- 帮助文档【对开发提供帮助】
- 注意使用时的版本统一
Package and import
1. 关于java语言当中的包机制:
a) 包又称为package,java中引用package这种语法机制主要是为了方便程序的管理。不同功能的类被分门别类放到不同的软件包当中,查找比较方便,管理比较方便,易维护。
b) 如何定义package?
i. 在java源程序的第一行上编写package语句。
ii. Package只能编写一个语句。
iii. 语法结构:
1. Package 报名;
c) 包名的命名规范:
i. 公司的域名倒叙 + 项目名 + 模块名 + 功能名
ii. 主要采用这种方式,重名的机率较低,因为公司域名具有全球唯一性
iii. 例如:
1. com.bjpowernode.oa.user.service
2. org.apache.tomact.core;
d) 包名要求全部小写,包名也是标识符,必须遵守标识符的命名规则
e) 一个包将来对应的是一个目录
f) 使用了package之后如何编译运行?
i. 使用了package机制之后,类名不再是test03了,类名是:com.szkjdx.javase.packagestudy.test03
ii. 编译:javac java源文件路径 (在硬盘上生成一个class文件:test03.class)
iii. 手动方式创建目录,将test03.class字节码文件放到指定的目录下
iv. 运行:java com.szkjdx.javase.packagestudy.test03
v. 另一种方式:编译 + 运行
1. Javac -d 编译之后存放路径 java源文件的路径
2. 例如:将F:\Hello.java文件编译之后放到C:\目录下
Java -d c:\ F:\Hello.java
3. Java -d . *.java
将当前路径中*.java编译之后存放到当前目录下
4. 运行:JVM的类加载器ClassLoader默认从当前路径下加载
a) 保证DOS命令窗口的路径先切换到com所在的路径,执行:
Java com.szkjdx.javase.packagestudy.test01
b)
2. Import语句来完成导入其他类,同一个包下的类不需要导入,不在同一个包下需要手动导入。
a) Import语法格式:
Import 类名;
Import 包名.*;
b) Import语句需要编写在package语句之下,class语句之上
c) Java.lang.*不需要手动引入,系统自动引入。
Lang:language语言包,是java语言的核心类,不需要手动引入
d) 最终结论:
什么时候需要import?
不是java.lang包下,并且不在同一个包下的时候,需要使用import进行引入
e) Eclipse导入类的快捷键:Ctrl + Shift + O
关于访问控制权限
访问控制权限修饰符:
- 访问控制权限修饰符来控制元素的访问范围
- 访问控制权限修饰符包括:
名称 | 访问范围 |
Public | 表示公开的,在任何位置都可以访问 |
Protected | 同包下、子类中可以访问 |
缺省 | 同包下可以访问 |
Private | 表示私有的,只能在本类中访问 |
- 访问控制权限修饰符可以修饰类、变量、方法、……
- 当某个数据只希望子类使用,使用Protected进行修饰
- 修饰符的范围:
Private < 缺省 < protected < public
- 类只能采用public和缺省的修饰符进行修饰。【内部类除外】
1. package com.sust.cst.javase.selflearning.c09_accessControlPermission.t01;
2.
3. public class Test01 {
4. public static void main(String[] args) {
5. User u = new User();
6. System.out.println(u.i);
7. System.out.println(u.j);
8. }
9. }
1. package com.sust.cst.javase.selflearning.c09_accessControlPermission.t01;
2.
3. public class User {
4.
5. //受保护的
6. protected int i = 10;
7.
8. //缺省的
9. int j = 20;
10. }
1. package com.sust.cst.javase.selflearning.c09_accessControlPermission.t02;
2.
3. import com.sust.cst.javase.selflearning.c09_accessControlPermission.t01.User;
4.
5. public class Driver extends User {
6. public void m(){
7. System.out.println(this.i);
8. //System.out.println(this.j);
9. }
10. }
1. package com.sust.cst.javase.selflearning.c09_accessControlPermission.t02;
2.
3. import com.sust.cst.javase.selflearning.c09_accessControlPermission.t01.User;
4.
5. public class UserTest {
6. public static void main(String[] args) {
7. User u = new User();
8. //System.out.println(u.i);
9. //System.out.println(u.j);
10. }
11. }
关于单例模式
设计模式:可以重复利用的解决方案
单例模式是23种设计模式中最简单的一种设计模式
为了解决什么问题?
为了保证JVM中某一个类型的java对象永远只有一个。
为了节省内存的开销
实现单例模式三要素:
- 构造方法私有化
- 对外提供公开的静态的获取当前类型对象的方法
- 提供一个当前类型的静态变量
设计模式从结构上分为三类:创建型、结构性、行为型
单例模式为创建型设计模式
单例模式分为两种:
- 饿汉式单例
特点:在类加载阶段就创建了对象
- 懒汉式单例(相对好一点)
特点:用到对象的时候才会创建对象
1. package com.sust.cst.javase.selflearning.c10_Singleton;
2.
3. public class User {
4. }
1. package com.sust.cst.javase.selflearning.c10_Singleton;
2. /*
3. 实现单例模式
4. * */
5. public class Singleton {
6.
7. //静态变量
8. private static Singleton s;
9.
10. //将构造方法私有化
11. private Singleton(){}
12.
13. //对外提供一个公开的获取Singleton对象的方法
14. public static Singleton getInstance(){
15.
16. if(s == null){
17. s = new Singleton();
18. }
19.
20. return s;
21. }
22. }
1. package com.sust.cst.javase.selflearning.c10_Singleton;
2.
3. /*
4. 饿汉式单例模式
5. */
6. public class Custormer {
7.
8. //类加载只执行一次
9. private static Custormer c = new Custormer();
10.
11. //构造方法私有化
12. private Custormer(){}
13.
14. //提供公开的方法
15. public static Custormer getInstance(){
16.
17. return c;
18. }
19. }
1. package com.sust.cst.javase.selflearning.c10_Singleton;
2.
3. /*
4. 单例模式是23种设计模式种最简单的一种设计模式
5. */
6. public class UserTest {
7. public static void main(String[] args) {
8. User u1 = new User();
9. User u2 = new User();
10.
11.
12. //==两边如果是基本数据类型,可以比较两个基本数据类型是否相等
13. //==两边如果是引用数据类型,则比较的是内存地址。
14. System.out.println(u1 == u2); //false
15.
16. Singleton s1 = Singleton.getInstance();
17. Singleton s2 = Singleton.getInstance();
18. System.out.println(s1 == s2); //true
19.
20. Custormer c1 = Custormer.getInstance();
21. Custormer c2 = Custormer.getInstance();
22. System.out.println(c1 == c2); //true
23. }
24. }
super关键字
- super不是引用类型,super中存储的不是内存地址,super指向的不是父类对象
- super代表的是当前子类对象中的父类型特征。
- 什么时候使用super?
- 子类和父类中都有某个数据.
- 例如:子类和父类中都有name这个属性,如果要在子类中访问父类中的name属性,则需要加super.
- super可以用在什么地方
- super可以用在成员方法中,不能用在静态方法中
- 可以用在构造方法中
- 语法:super(实参);
- 作用:通过子类的构造方法去调用父类的构造方法
- 语法规则:一个构造方法第一行如果没有this(…);,也没有显示的去调用super();系统会默认调用super(…);
- super();的调用只能放在构造方法的第一行
- super();和this();不能共存
- super();调用了父类中的构造方法,但是并不会创建父类对象
- 在java语言中,只要是创建java对象,那么Object中的无参数构造方法一定会执行
- 单例模式的缺点:
- 构造方法私有化(单例模式的类型没有子类,无法被继承)
1. package com.sust.cst.javase.selflearning.c11_super;
2.
3. public class Employee {
4.
5. String name = "张三";
6. public void work(){
7. System.out.println("员工在工作");
8. }
9. }
1. package com.sust.cst.javase.selflearning.c11_super;
2.
3. public class Manager extends Employee {
4.
5. String name = "李四";
6.
7. //子类将父类中的work方法重写了
8. @Override
9. public void work() {
10. System.out.println("经理在工作");
11. }
12.
13. public void m1(){
14. //this.work();
15. work();
16. super.work();
17.
18. System.out.println(this.name);
19. System.out.println(super.name);
20. }
21.
22. //super和this相同,都不能用在静态上下文中
23. public static void m2(){
24. //System.out.println(super.name);
25. }
26. }
1. package com.sust.cst.javase.selflearning.c11_super;
2.
3. public class Test01 {
4. public static void main(String[] args) {
5. Manager m = new Manager();
6.
7. m.m1();
8. }
9. }
1. package com.sust.cst.javase.selflearning.c11_super;
2.
3. public class Account {
4. //
5. private String actno;
6. private double balance;
7.
8. public String getActno() {
9. return actno;
10. }
11.
12. public void setActno(String actno) {
13. this.actno = actno;
14. }
15.
16. public double getBalance() {
17. return balance;
18. }
19.
20. public void setBalance(double balance) {
21. this.balance = balance;
22. }
23.
24. public Account(String actno, double balance) {
25. this.actno = actno;
26. this.balance = balance;
27. }
28.
29. public Account() {
30. System.out.println("Account的无参数构造方法执行!");
31. }
32. }
1. package com.sust.cst.javase.selflearning.c11_super;
2.
3. public class DebitAccount extends Account {
4.
5. private double debit;
6.
7. public DebitAccount(String actno, double balance, double debit) {
8.
9. //通过子类的构造方法去调用父类的构造方法,作用是:给当前子类对象中的父类型特征赋值
10. super(actno, balance);
11. this.debit = debit;
12. }
13.
14. public DebitAccount() {
15. //super();
16. //super("001", 1000.1);
17. }
18.
19. public double getDebit() {
20. return debit;
21. }
22.
23. public void setDebit(double debit) {
24. this.debit = debit;
25. }
26. }
1. package com.sust.cst.javase.selflearning.c11_super;
2.
3. public class Test02 {
4. public static void main(String[] args) {
5. DebitAccount da = new DebitAccount();
6. }
7. }
抽象类abstract
- 如何定义抽象类
class关键字前加abstract
- 抽象类无法被实例化
- 虽然抽象类没有办法实例化,但是抽象类也有构造方法,该构造方法是给子类创建对象用的
- 抽象类中可以定义抽象方法:
抽象方法的语法:在方法的修饰符列表中加abstract关键字,并且抽象方法应该以“;”来结束,不能带有“{}“
例:public abstract void m1();
- 抽象类中不一定有抽象方法,但是抽象方法必须出现在抽象类中。
- 一个非抽象的类继承抽象类,必须将抽象类中的抽象方法覆盖,实现,重写
- 抽象类不能被final修饰,抽象方法不能被final修饰
1. package com.sust.cst.javase.selflearning.c12_abstract;
2.
3. public abstract class A {
4.
5. A(){
6. System.out.println("A...");
7. }
8.
9. public abstract void m1();
10.
11. public static void main(String[] args) {
12.
13. A a = new B();
14.
15. //抽象类无法创建对象
16. //A a = new A();
17. }
18. }
19.
20. class B extends A{
21. B(){
22. super(); //父类的构造方法虽然调用了,但是没有创建父类对象
23. System.out.println("B...");
24. }
25.
26. @Override
27. public void m1() {
28.
29. }
30. }
接口interface
接口也是一种引用类型,可以等同看作类
- 如何定义接口,语法:
[修饰符] interface 接口名{}
- 接口中只能出现:常量、抽象方法
- 接口其实是一个特殊的抽象类,特殊在接口是完全抽象的
- 接口中没有构造方法,无法被实例化
- 接口和接口之间可以多继承
- 一个类可以实现多个接口【这里的实现可以等同看作”继承”】
- 一个非抽象的类实现接口,需要将接口中所有的方法实现/重写/覆盖
1. package com.sust.cst.javase.selflearning.c13_interface;
2.
3. public interface A {
4.
5. //常量(必须用public static final修饰)
6. public static final String SUCCESS = "success";
7. public static final double PI = 3.1415926;
8.
9. //public static final 是可以省略的
10. byte MAX_VALUE = 120;
11.
12. //抽象方法 接口中所有的抽象方法都是public abstract
13. public abstract void m1();
14.
15. //public abstract 是可以省略的
16. void m2();
17. }
18.
19. interface B {
20. void m1();
21. }
22.
23. interface C {
24. void m2();
25. }
26.
27. interface D {
28. void m3();
29. }
30.
31. interface E extends B,C,D{
32. void m4();
33. }
34.
35. //implements是实现的意思,是以恶搞关键字
36. //implements和extends意义相同
37. class MyClass implements B,C{
38.
39. @Override
40. public void m1() {
41.
42. }
43.
44. @Override
45. public void m2() {
46.
47. }
48. }
49.
50. class F implements E{
51.
52. @Override
53. public void m1() {
54.
55. }
56.
57. @Override
58. public void m2() {
59.
60. }
61.
62. @Override
63. public void m3() {
64.
65. }
66.
67. @Override
68. public void m4() {
69.
70. }
71. }
- 接口的作用
- 可以使项目分层,所有层都面向接口开发,开发效率提高了
- 可以使代码和代码之间的耦合度降低,使项目变得可插拔,可以随意切换
- 如何选择接口还是抽象类?
- 如果抽象类和接口都能实现功能,则优先选择接口
- 接口可以多实现,多继承
- 一个类除了实现接口外,还可以去继承其他类(保留了类的继承)
- 接口可以多继承,一个类可以实现多个接口,抽象类的类和类之间只能实现单继承
- 抽象类可以半抽象,接口完全抽象
- 最好面向抽象编程,可以使项目的可扩展能力增强
1. package com.sust.cst.javase.selflearning.c13_interface.Car;
2.
3. /*
4. 汽车和发动机之间的接口
5. 生产汽车的厂家面向接口生产
6. 生产发动机的厂家面向接口生产
7. */
8.
9. public interface Engine {
10. void start();
11. }
1. package com.sust.cst.javase.selflearning.c13_interface.Car;
2.
3. public class Car {
4.
5. //引擎
6. //面向接口编程
7. Engine e;
8.
9. //Constructor
10. Car(Engine e){
11. this.e = e;
12. }
13.
14. //汽车能够测试引擎
15. public void testEngine(){
16. e.start();//面向接口调用
17. }
18. }
1. package com.sust.cst.javase.selflearning.c13_interface.Car;
2.
3. public class HONDA implements Engine{
4.
5. @Override
6. public void start() {
7. System.out.println("HONDA启动");
8. }
9. }
1. package com.sust.cst.javase.selflearning.c13_interface.Car;
2.
3. public class YAMAHA implements Engine{
4. @Override
5. public void start() {
6. System.out.println("YAMAHA 启动");
7. }
8. }
1. package com.sust.cst.javase.selflearning.c13_interface.Car;
2.
3. public class Test {
4. public static void main(String[] args) {
5. //1.生产引擎
6. Engine e1 = new YAMAHA();
7. //2.生产汽车
9. Car c1 = new Car(e1);
10.
11. //3.测试引擎
12. c1.testEngine();
13.
14. //换HONDA
15. c1.e = new HONDA();
16. c1.testEngine();
17. }
18. }
Object类
toString(); *
SUN在Object类中设计toString方法的目的:返回java对象的字符串表示形式
在现实的开发过程中,Object里边的toString方法已经不够用了,因为Object的toString方法实现的结果不满意
Object中的toSting方法就是要被重写的
SUN实现的toString方法
1. public String toString() { 2. return getClass().getName() + "@" + Integer.toHexString(hashCode()); 3. }
Object中的toString方法返回:类名@java对象在内存中的地址经过哈希算法的出的int类型值再转换成十六进制。
这个输出结果可以等同看作java对象在堆中的内存地址
public boolean equals(Object obj); *
Object中的equals方法:
public boolean equals(Object obj) { return (this == obj); }
o1.equals(o2); o1是this,o2是obj
== 两边如果是引用类型,则比较内存地址,地址相同是true,反之则false
Object中的equals方法比较的是两个引用的内存地址
java对象中的equals方法的设计目的,是判断两个对象是否一样。
在java中比较两个字符串是否一致,不能用“==”
只能用String类的equals方法
1. package com.sust.cst.javase.selflearning.c14_Object.t02_equals; 2. 3. public class Test01 { 4. public static void main(String[] args) { 5. Object o1 = new Object(); 6. Object o2 = new Object(); 7. 8. boolean b1 = o1.equals(o2); 9. 10. System.out.println(b1); //false 11. 12. Star s1 = new Star("aaaa", 100); 13. Star s2 = new Star("aaaa", 100); 14. Star s3 = new Star("aaaa", 110); 15. 16. System.out.println(s1.equals(s2)); //true 17. System.out.println(s2.equals(s3)); //false 18. } 19. } 20. 21. class Star{ 22. String name; 23. int id; 24. 25. public Star(String name, int id) { 26. this.name = name; 27. this.id = id; 28. } 29. 30. //Object中的equals方法比较的是内存地址, 31. //在现实的业务逻辑当中不应该比较内存地址,应该比较内容 32. //所以Object中的equals方法也需要重写 33. //根据需求规定重写equals方法,需求规定:如果身份证号一致,并且名字也一致,则代表同一个人 34. //s1.equals(s2); 35. @Override 36. public boolean equals(Object obj) { 37. 38. if(this == obj) 39. return true; 40. 41. if(obj instanceof Star) { 42. Star s = (Star) obj; 43. 44. if (this.id == s.id) { 45. if (this.name.equals(s.name)) 46. return true; 47. } 48. } 49. return false; 50. } 51. }
1. package com.sust.cst.javase.selflearning.c14_Object.t02_equals; 2. 3. public class Test02 { 4. public static void main(String[] args) { 5. String s1 = new String("ABC"); 6. String s2 = new String("ABC"); 7. 8. System.out.println(s1 == s2); //false 9. 10. //String已经重写了equals 11. System.out.println(s1.equals(s2)); //true 12. } 13. }
finalize();
垃圾回收器(GC,Garbage Collection)
finalize方法什么时候调用?
- finalize方法每个java对象都有
- finalize方法不需要程序员去调用,由系统自动调用
- java对象如果没有更多的引用指向它,则该java对象成为垃圾数据,等待垃圾回收器的回收,垃圾回收器在回收这个java对象之前会自动调用该对象的finalize方法
finalize方法是该对象马上就要被回收了,例如:需要释放资源,则可以在该方法中释放
1. package com.sust.cst.javase.selflearning.c14_Object.t03_finalize; 2. 3. public class Test01 { 4. public static void main(String[] args) { 5. Person p1 = new Person(); 6. p1 = null;//没有引用再指向它,等待回收 7. 8. //程序员只能“建议”垃圾回收器回收垃圾 9. System.gc();//运行垃圾回收器 10. } 11. 12. static class Person{ 13. 14. //重写Object中的finalize方法 15. @Override 16. public void finalize() throws Throwable { 17. System.out.println(this + "马上就要被回收了!"); 18. //让一个引用再次重新指向这个对象,该对象不是垃圾数据,不会被垃圾回收器回收 19. Person p = this;//挽救这个对象 20. } 21. } 22. }
public native int hashCode();
1. package com.sust.cst.javase.selflearning.c14_Object.t04_hashCode; 2. 3. public class Test01 { 4. public static void main(String[] args) { 5. 6. //hashCode方法返回的是该对象的哈希码值 7. //java对象的内存地址经过哈希算法得出的int类型的数值 8. Test01 t = new Test01(); 9. 10. System.out.println(t.hashCode()); //284720968 11. } 12. }
clone();
创建并返回一个对象的副本,为了保证原数据的结构不被破坏
内部类
内部类的重要作用:可以访问外部类中的私有数据
静态内部类
- 静态内部类可以等同看作静态变量。
- 静态内部类可以直接访问外部类的静态数据,无法直接访问成员。
1. package com.sust.cst.javase.selflearning.c15_internalClass.t01_staticInnerClass;
2.
3. public class OuterClass {
4.
5. //静态变量
6. static String s1 = "A";
7.
8. //成员变量
9. private String s2 = "B";
10.
11. //静态方法
12. private static void m1(){
13. System.out.println("static m1 method excute!");
14. }
15.
16. //成员方法
17. private void m2(){
18. System.out.println("m2 method excute!");
19. }
20.
21. //静态内部类
22. //可以用访问控制权限的修饰符修饰
23. //public protected private 缺省
24. static class InnerClass{
25.
26. //定义静态方法
27. public static void m3(){
28. System.out.println(s1);
29. m1();
30.
31. //System.out.println(s2);
32. //m2();
33. }
34.
35. //成员方法
36. public void m4(){
37. System.out.println(s1);
38. m1();
39.
40. //System.out.println(s2);
41. //m2();
42. }
43. }
44.
45. public static void main(String[] args) {
46.
47. //执行m3
48. OuterClass.InnerClass.m3();
49.
50. //执行m4
51. InnerClass innerClass = new OuterClass.InnerClass();
52. innerClass.m4();
53. }
54. }
成员内部类
- 成员内部类可以等同看作成员变量
- 成员内部类中不能有静态声明
- 成员内部类可以访问外部类所有的数据
1. package com.sust.cst.javase.selflearning.c15_internalClass.t02_memberInnerClass;
2.
3. public class OuterClass {
4.
5. //静态变量
6. static String s1 = "A";
7.
8. //成员变量
9. private String s2 = "B";
10.
11. //静态方法
12. private static void m1(){
13. System.out.println("static m1 method excute!");
14. }
15.
16. //成员方法
17. private void m2(){
18. System.out.println("m2 method excute!");
19. }
20.
21. //成员内部类
22. //可以用访问控制权限的修饰符修饰
23. //public protected private 缺省
24. class InnerClass{
25.
26. //不能定义静态方法
27. //public static void m3(){}
28.
29. //成员方法
30. public void m4(){
31. System.out.println(s1);
32. m1();
33.
34. //System.out.println(s2);
35. //m2();
36. }
37. }
38.
39. public static void main(String[] args) {
40.
41. //创建外部类对象
42. OuterClass outerClass = new OuterClass();
43.
44. InnerClass innerClass = outerClass.new InnerClass();
45.
46. innerClass.m4();
47. }
48. }
局部内部类 *
局部内部类等同于局部变量
重点:局部内部类再访问局部变量的时候,局部变量必须使用final修饰
1. package com.sust.cst.javase.selflearning.c15_internalClass.t03_localInnerClass;
2.
3. public class OuterClass {
4.
5. //方法
6. public void m1(){
7. //局部变量
8. final int i = 10;
9.
10. //局部内部类
11. //局部内部类不能用访问控制权限修饰符修饰
12. class InnerClass{
13.
14. //局部内部类中不能有静态声明
15. //public static void m1(){}
16.
17. //成员方法
18. public void m2(){
19. System.out.println(i); //10
20. }
21. }
22.
23. //m1方法执行 ...--> 10
24. //如果不加final,则不能更改i,否则会输出其他结果
25.
26. //只能在m1方法中调用m2
27. InnerClass innerClass = new InnerClass();
28. innerClass.m2();
29. }
30.
31. public static void main(String[] args) {
32. //InnerClass无法在外部创建对象
33.
34. OuterClass outerClass = new OuterClass();
35. outerClass.m1();
36. }
37. }
匿名内部类 *
指的是类没有名字
优点:少定义一个类
缺点:无法重复使用
1. package com.sust.cst.javase.selflearning.c15_internalClass.t04_anonymousInnerClass;
2.
3. public class Test01 {
4.
5. //静态方法
6. public static void test(CustomerService customerService){
7. customerService.logout();
8. }
9.
10. public static void main(String[] args) {
11.
12. //调用test方法
13. //方法1
14. // test(new CustomerServiceImpl());
15.
16. //方法2 使用匿名内部类的方式执行test方法
17. //整个"new CustomerService() {...}"就是一个匿名内部类
18. test(new CustomerService() {
19. @Override
20. public void logout() {
21. System.out.println("系统已经安全退出!");
22. }
23. });
24.
25. }
26.
27.
28. }
29.
30. //接口
31. interface CustomerService{
32.
33. //退出系统
34. void logout();
35. }
36.
37. //方法1:编写一个类实现CustomerService接口
38. /*class CustomerServiceImpl implements CustomerService{
39. public void logout(){
40. System.out.println("系统已经安全退出!");
41. }
42. }*/
类与类之间关系
泛化关系
类和类之间的继承关系以及接口与接口之间的继承关系
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t01_generalizationRelationship;
2.
3. public class A {
4. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t01_generalizationRelationship;
2.
3. //B继承A,A和B之间的关系称为泛化关系
4. public class B extends A {
5. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t01_generalizationRelationship;
2.
3. public interface C {
4. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t01_generalizationRelationship;
2.
3. //D和C两个接口之间继承也属于泛化关系
4. public interface D extends C {
5. }
实现关系
类对接口的实现
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t02_realizeRelationship;
2.
3. public interface A {
4. void m1();
5. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t02_realizeRelationship;
2.
3. //B类实现了A接口,它们之间属于实现关系
4. public class B implements A{
5.
6. @Override
7. public void m1() {
8. System.out.println("实现关系");
9. }
10. }
关联关系
类与类之间的连接,一个类可以知道另一个类的属性和方法,在java语言中使用成员变量体现
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t03_connectionRelation;
2.
3. public class Self {
4.
5. //Field
6. String name;
7.
8. //在当前类中含有其他类的引用
9. //在当前对象中含有指向其他对象的引用
10. //朋友
11. Friend f; //Self和Friend就是关联关系
12.
13. public Self(Friend f) {
14. this.f = f;
15. }
16. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t03_connectionRelation;
2.
3. public class Friend {
4.
5. String name;
6. String addr;
7. String tel;
8.
9. public Friend(String addr) {
10. this.addr = addr;
11. }
12. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t03_connectionRelation;
2.
3. import com.sust.cst.javase.selflearning.c11_super.Servlet;
4.
5. public class Test01 {
6. public static void main(String[] args) {
7. Friend f = new Friend("北京朝阳");
8.
9. //建立关联关系
10. Self me = new Self(f);
11.
12. //通过m可以获取朋友的住址
13. System.out.println(me.f.addr);
14. }
15. }
聚合关系
是关联关系的一种,是较强的关联关系,是整体和部分的关系,如: 汽车和轮胎,它与关联关系不同,关联关系的类处在同一个层次上,而聚合关系的类处在不平等的层次上,一个代表整体,一个代表部分,在java语言中使用实例变量体现。
整体不依赖部分,部分也不会依赖整体。
整体无法决定部分的生命周期。
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t04_aggregationRelationship;
2.
3. public class Student {
4. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t04_aggregationRelationship;
2.
3. import java.util.List;
4.
5. //Classroom就是整体,student就是部分
6. public class Classroom {
7.
8. //Classroom和List集合属于关联关系,在同一个层级上
9. //Classroom和Student属于聚合关系,一个是整体,一个是部分
10. List<Student> studentList;//studentList就是部分
11. }
12.
13. //集合:容器
合成关系
比聚合关系强的关联关系,如:人和四肢,整体对象决定部分对象的生命周期,部分对象每一时刻只与一个对象发生合成关系,在java语言中使用实例变量体现。
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t05_syntheticRelationship;
2.
3. public class Limbs {
4. }
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t05_syntheticRelationship;
2.
3. import java.util.List;
4.
5. public class Human {
6.
7. //人和List是关联关系
8. //人和四肢是合成关系,人是整体,四肢是部分
9. //合成关系和聚合关系是相似的,
10. // 区别的地方在整体和部分是紧密相连的,整体生命周期决定部分的生命周期。
11. List<Limbs> limbsList;
12.
13. }
依赖关系
是比关联关系弱的关系,在java语言中体现为返回值,参数,局部变量和静态方法调用。
1. package com.sust.cst.javase.selflearning.c16_relationshipBetweenClassesAndClasses.t06_dependency;
2.
3. public class Test {
4.
5. public void m1() {
6. //局部变量
7. User u = new User();//依赖关系
8. }
9. }
10.
11. class User{}
- is-a
继承
- is-like-a
类和接口之间的实现关系
- has-a
关联关系
异常处理
异常的基本概念
异常是什么?
- 异常模拟的是现实世界中不正常的事件
- java中采用类的形式去模拟异常
- 类是可以创建对象的,
NullPointerException e;
e是引用类型,e中保存的内存地址指向堆中的对象
这个对象一定是NullPointerException类型
这个对象就表示真实存在的异常事件
NullPointerException是一类异常
“抢劫”就是一类异常, à 类
张三被抢劫就是一个异常事件 à 对象
异常机制的作用
程序发生异常事件之后,为我们输出了详细的信息,程序员通过这个信息可以堆程序进行一些处理,使程序更加健壮
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. public class Test01 {
4. public static void main(String[] args) {
5. int a = 10;
6. int b = 0;
7. int c = a/b;
8.
9. /*
10. 以上程序编译通过了,但是运行时出现了异常,表示发生某个异常事件
11. JVM控制台输出如下信息:
12. Exception in thread "main" java.lang.ArithmeticException: / by zero
13. at com.sust.cst.javase.selflearning.c17_Exception.ExceptionTest01.main(ExceptionTest01.java:7)
14.
15. 本质:程序执行过程中发生了算数异常,JVM为我们创建了一个ArithmeticException类型的对象。
16. 并且这个对象中包含了详细的异常信息,并且JVM将这个对象中的信息输出到了控制台。
17. * */
18.
19. //上面的代码出现了异常,没有处理,下面的代码不会执行,直接退出JVM
20. System.out.println("hello world!");
21. }
22. }
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. public class Test02 {
4.
5. public static void main(String[] args) {
6. int a = 10;
7. int b = 0;
8.
9. if(b != 0) {
10. int c = a / b;
11. System.out.println(a + "/" + b + "=" + c);
12. }
13. else
14. System.out.println("除数不能为0");
15. }
16. }
异常的分类
异常的捕获和处理
处理异常有两种方式:
声明抛出 throws
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. import java.io.*;
4.
5. //声明抛出
6. //在方法声明的位置上使用throws关键字向上抛出异常
7. public class Test03 {
8. //public static void main(String[] args) throws FileNotFoundException{
9. //public static void main(String[] args) throws IOException {
10. public static void main(String[] args) throws Exception{
11. /*
12. FileInputStream 输入流
13. 在java.io类中
14. 用于读取在硬盘中的文件
15. */
16.
17. //创建文件输入流,读取文件
18. //思考:java编译器使如何知道以下的代码执行过程中可能出现异常,
19. // java编译器使如何知道这个异常发生的机率比较高呢?
20. //java编译器不是那么智能,因为FileInputStream这个构造方法在声明的位置上使用了throws FileNotFoundException
21. FileInputStream fileInputStream = new FileInputStream("c:/ab.txt");
22.
23. /*以上程序编译不通过
24. Error:(16, 43) java: 未报告的异常错误java.io.FileNotFoundException; 必须对其进行捕获或声明以便抛出
25. */
26. }
27. }
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. import java.io.*;
4.
5. //深入throws
6. public class Test04 {
7. public static void main(String[] args) {
8.
9. //m1();
10.
11. //使用throws处理异常不是真正的处理异常而是推卸责任
12. //谁调用的就会抛给谁
13. //上面的m1方法如果出现了异常,因为采用的是上抛,给了JVM,JVM遇到了这个异常就会退出JVM,下面的代码不会执行
14. //System.out.println("hello world!");
15.
16. //真正处理
17. try {
18. m1();
19. } catch (Exception e) {
20. }
21.
22. System.out.println("hello world!");
23. }
24.
25. public static void m1() throws Exception {
26. m2();
27. }
28.
29. public static void m2() throws Exception {
30. m3();
31. }
32.
33. public static void m3() throws Exception {
34. new FileInputStream("c:/ab.txt");//FileInputStream构造方法声明位置上使用了throws
35. }
36. }
37.
38. //在程序运行过程中发生了FileNotFoundException类型的异常
39. //JVM为我们创建了一个FileNotFoundException类型的对象
40. //该对象中携带以下信息:
41. //JVM负责将该对象的信息打印到控制台
42. //并且JVM停掉了程序的运行。
43. /*
44. Exception in thread "main" java.io.FileNotFoundException: c:\ab.txt (系统找不到指定的文件。)
45. at java.base/java.io.FileInputStream.open0(Native Method)
46. at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
47. at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
48. at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
49. at com.sust.cst.javase.selflearning.c17_Exception.Test04.m3(Test04.java:26)
50. at com.sust.cst.javase.selflearning.c17_Exception.Test04.m2(Test04.java:22)
51. at com.sust.cst.javase.selflearning.c17_Exception.Test04.m1(Test04.java:18)
52. at com.sust.cst.javase.selflearning.c17_Exception.Test04.main(Test04.java:9)
53. */
捕捉 try…catch…
语法:
try{
可能出现异常的代码
}catch(异常类型1 异常变量){
处理异常的代码
}catch(异常类型2 变量){
处理异常的代码
}……
- catch语句块可以写多个
- 但是从上到下catch,必须从小类型异常到大类型异常进行捕捉
- try…catch…中最多执行1个catch语句块,执行结束之后try…catch…就结束了
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. /*
4. 处理异常的第二种方式:捕捉
5. try...catch...
6. */
7.
8. import java.io.*;
9.
10. public class Test05 {
11. public static void main(String[] args) {
12.
13. //以下代码编译无法通过,因为FileNotFoundException没有被处理
14. /*try{
15. //FileNotFoundException
16. FileInputStream fileInputStream = new FileInputStream("c:/ab.txt");
17. }catch (ArithmeticException e){ //捕获的算数异常
18. }*/
19.
20. //编译通过
21. /*
22. try{
23. //FileNotFoundException
24. FileInputStream fileInputStream = new FileInputStream("c:/ab.txt");
25. }catch (FileNotFoundException e){
26. }
27. */
28. //以下程序编译无法通过
29. //因为还有更多的IOException没有处理
30. /*try{
31. //FileNotFoundException
32. FileInputStream fileInputStream = new FileInputStream("c:/ab.txt");
33. fileInputStream.read();
34. }catch (FileNotFoundException e){
35.
36. }*/
37.
38. //编译通过
39. try{
40. //FileNotFoundException
41. FileInputStream fileInputStream = new FileInputStream("c:/ab.txt");
42. fileInputStream.read();
43. }catch (FileNotFoundException e){
44.
45. }catch(IOException e){
46.
47. }
48.
49. //编译通过
50. //相对于上一种方法,这种方式处理异常比较模糊
51. /* try{
52. //FileNotFoundException
53. FileInputStream fileInputStream = new FileInputStream("c:/ab.txt");
54. fileInputStream.read();
55. }catch (IOException e){
56.
57. }
58. */
59. //编译无法通过
60. //catch可以写多个,但必须从上到下,从小到大
61. /*try{
62. //FileNotFoundException
63. FileInputStream fileInputStream = new FileInputStream("c:/ab.txt");
64. fileInputStream.read();
65. }catch (IOException e){
66.
67. }catch (FileNotFoundException e){
68.
69. }*/
70. }
71. }
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. import java.io.FileInputStream;
4. import java.io.FileNotFoundException;
5. import java.io.IOException;
6.
7. public class Test06 {
8. //编译无法通过
9. //IOException没有处理
10. /*public static void main(String[] args) throws FileNotFoundException {
11.
12. FileInputStream fileInputStream = new FileInputStream("abc");
13. fileInputStream.read();
14. }*/
15.
16. //通过
17. /*public static void main(String[] args) throws FileNotFoundException, IOException {
18. FileInputStream fileInputStream = new FileInputStream("abc");
19. fileInputStream.read();
20. }*/
21.
22. //通过
23. /*public static void main(String[] args) throws IOException {
24. FileInputStream fileInputStream = new FileInputStream("abc");
25. fileInputStream.read();
26. }
27. */
28.
29. public static void main(String[] args) {
30. try{
31. //程序执行到此处发生了FileNotFoundException类型的异常
32. //JVM会自动创建一个FileNotFoundException类型的对象,将该对象的内存地址赋值给catch语句块中的e变量
33. FileInputStream fileInputStream = new FileInputStream("abc");
34.
35. //上面的代码出现了异常,try语句块的代码不再继续执行,直接进入catch语句块中执行
36. System.out.println("Test");
37.
38. fileInputStream.read();
39. }catch (FileNotFoundException e){ //e内存地址指向堆中的那个对象是“FileNotFoundException”类型的事件
40. System.out.println("读取的文件不存在!");
41.
42. //FileNotFoundException将Object中的toString方法重写了
43. System.out.println(e);//java.io.FileNotFoundException: abc (系统找不到指定的文件。)
44. }catch (IOException e){
45. System.out.println(" 其他IO异常");
46. }
47.
48. System.out.println("ABC");
49.
50. }
51. }
getMessage()和printStackTrace()
- getMessage():取得异常描述信息
- printStackTrace():取得异常的堆栈信息(比较适合于程序调试阶段)
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. import java.io.*;
4.
5. public class Test07 {
6. public static void main(String[] args) {
7. try{
8. FileInputStream fileInputStream = new FileInputStream("c:/abc.txt");
9.
10. //JVM为我们执行了以下代码
11. //FileNotFoundException e = new FileNotFoundException("c:\\abc.txt (系统找不到指定的文件。)");
12.
13. }catch (FileNotFoundException e){
14. //打印异常堆栈信息
15. //一般情况下都会使用该方式去调试程序
16. //该方法用的较多
17. //e.printStackTrace();
18.
19. /*
20. java.io.FileNotFoundException: c:\abc.txt (系统找不到指定的文件。)
21. at java.base/java.io.FileInputStream.open0(Native Method)
22. at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
23. at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
24. at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
25. at com.sust.cst.javase.selflearning.c17_Exception.Test07.main(Test07.java:8)
26. */
27.
28. //这种方法用的较少,因为返回的信息太少
29. String msg = e.getMessage();
30. System.out.println(msg); //c:\abc.txt (系统找不到指定的文件。)
31. }
32.
33. //这段代码会执行
34. System.out.println("ABC");
35. }
36. }
finally语句块
- finally语句块可以直接和try语句块连用。try…finally…
- try…catch…finally…也可以
- 在finally语句块中的代码是一定会执行的,所以通常在程序中为了保证某资源一定会释放,所以一般在finally语句块中释放资源
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. import java.io.*;
4.
5. public class Test08 {
6.
7. public static void main(String[] args) throws Exception {
8.
9. /*try{
10. System.out.println("ABC");
11. return;
12. }finally {
13. System.out.println("Test finally");
14. }*/
15.
16. /*try{
17. FileInputStream fileInputStream = new FileInputStream("acv");
18.
19. //不会执行
20. System.out.println("tttt");
21. }finally {
22.
23. //会执行
24. System.out.println("Test finally 02");
25. }*/
26.
27. //只要在执行finally语句块之前退出了jvm,则finally语句块不会执行
28. try{
29. //退出JVM
30. System.exit(0);
31. }finally {
32.
33. //不会执行
34. System.out.println("Test finally 03");
35. }
36. }
37. }
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. public class Test09 {
4. public static void main(String[] args) {
5. int i = m1();
6. System.out.println(i); //10
7. }
8.
9. public static int m1(){
10.
11. int i = 10;
12.
13. try{
14. i = 10;
15. return i;
16. }finally {
17. i++;
18. System.out.println("m1()的i = " + i); //11
19. }
20.
21. //以上代码的执行原理
22. /*try{
23. int temp = i;
24. return temp;
25. }finally {
26. i++;
27. System.out.println("m1()的i = " + i);
28. }*/
29. }
30. }
1. package com.sust.cst.javase.selflearning.c17_Exception;
2.
3. import java.io.FileInputStream;
4. import java.io.FileNotFoundException;
5. import java.io.IOException;
6.
7. public class Test10 {
8.
9. public static void main(String[] args) {
10.
11. //必须在外部声明
12. FileInputStream fileInputStream = null;
13.
14. try{
15. fileInputStream = new FileInputStream("avb");
16. }catch(FileNotFoundException e){
17. e.printStackTrace();
18. }finally {
19.
20. //为了保证资源一定释放
21. if(fileInputStream != null){
22. try{
23. fileInputStream.close();
24. }catch(IOException e){
25. e.printStackTrace();
26. }
27. }
28. }
29.
30. }
31. }
自定义异常
如何手动抛出异常以及如何自定义异常
1. package com.sust.cst.javase.selflearning.c17_Exception.t03_customException;
2.
3. /*
4. 自定义无效名字异常
5. 1.编译时异常,直接继承Exception
6. 2.运行时异常,直接继承RuntimeException
7. */
8.
9. //public class IllegalNameException extends RuntimeException{ //运行时异常
10. public class IllegalNameException extends Exception{ //编译时异常
11.
12. //定义异常一般提供两个构造方法
13. public IllegalNameException(){}
14.
15. public IllegalNameException(String msg){
16. super(msg);
17. }
18. }
1. package com.sust.cst.javase.selflearning.c17_Exception.t03_customException;
2.
3. //客户相关的业务
4. public class CustomerService {
5.
6. //对外提供注册的方法
7. public void register(String name) throws IllegalNameException{
8.
9. //完成注册
10. if(name.length() < 6){
11. //异常
12. //创建异常对象
13. //IllegalNameException e = new IllegalNameException("用户名长度不能少于6位!");
14.
15. //手动抛出异常
16. //throw e;
17.
18. throw new IllegalNameException("用户名长度不能少于6位");
19. }
20.
21. //如果代码能执行到此处,说明用户名是合法的
22. System.out.println("注册成功");
23. }
24. }
1. package com.sust.cst.javase.selflearning.c17_Exception.t03_customException;
2.
3. /*
4. 模拟注册
5. */
6. public class Test01 {
7. public static void main(String[] args) throws IllegalNameException {
8.
9. //假如用户提供的用户名如下
10. String username = "aaaaaaa";
11.
12. //注册
13. CustomerService customerService = new CustomerService();
14.
15. try {
16. customerService.register(username);
17. } catch (IllegalNameException e) {
18. System.out.println(e.getMessage());
19. }
20. }
21. }
方法覆盖与异常
重写方法不能比被重写的方法抛出更宽泛的异常
1. package com.sust.cst.javase.selflearning.c17_Exception.t04_methodCoverageAndException;
2.
3. /*
4. 重写的方法不能比被重写的方法抛出更宽泛的异常
5. */
6.
7. import java.io.FileNotFoundException;
8. import java.io.IOException;
9.
10. public class Test11 {
11. }
12.
13. /*class A {
14. public void m1() {
15. }
16. }
17.
18. //子类永远无法抛出比父类更多的异常
19. class B extends A {
20. public void m1() throws Exception {
21. }
22. }*/
23.
24. class A{
25. //public void m1() throws FileNotFoundException{}
26. public void m1() throws IOException{}
27. }
28.
29. class B extends A{
30. //public void m1() throws IOException{}
31. public void m1() throws FileNotFoundException{}
32. }
数组
数组概要
- 数组是一种引用类型,数组是一种简单的数据结构
- 数组是一种简单的数据结构,线性的结构
- 数组是一个容器,可以用来存储其他元素。
数组是可以存储任意数据类型的元素
- 数组分为:一维数组,二维数组,多维数组
- 数组中存储的元素类型是统一的
- 数组长度不可改变,数组一旦创建,长度是不可变的,固定的。
1. package com.sust.cst.javase.selflearning.c18_array;
2.
3. public class Test01 {
4. public static void main(String[] args) {
5. //声明一个一维数组,用来存储int类型
6. int[] a1 = {100, 200, 150, 3030}; //静态初始化一维数组
7.
8. //boolean类型的数组
9. boolean[] b1= {true, false};
10. //String类型数组
11. String[] str1 = {"ab", "cd", "ed"};
12.
13. char[] c1 = {'a', 'b', 'c'};
14.
15. //Object数组
16. Object o1 = new Object();
17. Object o2 = new Object();
18. Object o3 = new Object();
19.
20. Object[] objs = {o1, o2, o3};
21.
22. }
23. }
- 数组中存储元素的类型是统一的,每个元素在内存中所占空间大小是相同的,直到数组的首元素的内存地址,要查找的元素只要知道下标就可以快速计算出偏移量,通过内存地址快速定位该元素,所以数组查找元素的效率较高。
- 随机的对数组进行增删元素,当增加元素的时候,为了保证数组中元素在空间存储上是有序的,所以被添加元素位置后面的所有元素都要向后移动,删除元素也是,后面所有元素要向前移动,所以数组的增删元素的效率很低。
一堆数组的声明和使用
- 初始化一维数组有两种方式:
-
静态初始化
-
1. package com.sust.cst.javase.selflearning.c18_array;
2.
3. public class Test02 {
4. public static void main(String[] args) {
5. //静态初始化一个int类型的一维数组
6. int[] a1 = {1, 2, 3};
7.
8. //取得第一个元素
9. System.out.println("第一个元素" + a1[0]);
10. //取得最后一个元素
11. System.out.println("最后一个元素" + a1[a1.length-1]);
12.
13. //取得个数
14. System.out.println("数组中元素的个数:" + a1.length);
15.
16. //遍历一维数组
17. for(int i = 0; i < a1.length; i++){
18. System.out.println(a1[i]);
19. }
20.
21. //将第二个元素修改为100
22. a1[1] = 100;
23. System.out.println("------------------------------");
24. //遍历一维数组
25. for(int i = 0; i < a1.length; i++){
26. System.out.println(a1[i]);
27. }
28. }
29. }
动态初始化
动态初始化一维数组,会先在堆内存中分配这个数组,并且数组中每一个元素都采用默认值。
float,double 0.0
byte,short,int,long 0
boolean false
char \u0000
引用 null
1. package com.sust.cst.javase.selflearning.c18_array;
2.
3. public class Test03 {
4. public static void main(String[] args) {
5. //动态初始化一维数组
6.
7. //动态声明一个int类型的数组,最多可以存储4个元素
8. int[] a1 = new int[4];
9.
10. //遍历
11. for(int i = 0; i < a1.length; i++)
12. System.out.println(a1[i]);
13.
14. //赋值
15. a1[0] = 2;
16. a1[1] = 21;
17. a1[2] = 22;
18. a1[3] = 23;
19.
20. //遍历
21. for(int i = 0; i < a1.length; i++)
22. System.out.println(a1[i]);
23.
24. //引用类型的数组
25. Object[] objs = new Object[3];
26.
27. for(int i = 0; i < objs.length; i++){
28. Object o = objs[i];
29. //o.toString(); 注意空指针异常,因为引用类型的数组默认值是null
30. System.out.println(o);//null
31. }
32. }
33. }
34.
35. /* --------------- 运行结果 ---------------
36. 0
37. 0
38. 0
39. 0
40. 2
41. 21
42. 22
43. 23
44. null
45. null
46. null
47. --------------- 运行结果 --------------- */
48.
49. /*
50. public void println(Object x) {
51. String s = String.valueOf(x);
52. synchronized (this) {
53. print(s);
54. newLine();
55. }
56. }
57.
58. public static String valueOf(Object obj) {
59. return (obj == null) ? "null" : obj.toString();
60. }
61. */
什么时候使用动态初始化?什么时候使用静态初始化?
- 无论是动态初始化还是静态初始化,最终的内存分配都是一样的。
- 如果在创建数组的时候知道数组中应该存储什么数据,这个时候当然采用静态初始化方式;
- 如果在创建数组的时候,无法预测到数组中存储什么数据,只是先开辟空间,则使用动态初始化的方式。
1. package com.sust.cst.javase.selflearning.c18_array;
2. /*
3. 什么时候使用动态初始化,什么时候使用静态初始化?
4.
5. */
6. public class Test04 {
7. public static void main(String[] args) {
8. //以下两种方式都是可以的
9. int[] a1 = {1,2,3};
10. int a2[] = {2,3,5};
11.
12. int a3[] = new int[4];
13. }
14. }
深入一维数组
1. package com.sust.cst.javase.selflearning.c18_array;
2.
3. import com.sust.cst.javase.selflearning.c07_final.finalTest01.A;
4.
5. /*
6. 深入一维数组
7. */
8. public class Test05 {
9. public static void main(String[] args) {
10.
11. //创建一个数组,这个数组既可以存储Dog也能存储Cat
12. Animal[] as = new Animal[4];
13.
14. //给数组每个元素赋值
15. Dog d1 = new Dog();
16. Dog d2 = new Dog();
17. Cat c1 = new Cat();
18. Cat c2 = new Cat();
19.
20. as[0] = d1;
21. as[1] = d2;
22. as[2] = c1;
23. as[3] = c2;
24.
25. //需求:遍历数组,取出每个对象,如果是Cat执行move方法;如果是Dog执行eat方法
26. for(int i = 0; i < as.length; i++){
27. Animal a = as[i];
28.
29. System.out.println(a);
30. //强制类型转换(向下转换)
31. if(a instanceof Cat){
32. Cat c = (Cat)a;
33. c.move();
34.
35. }else if(a instanceof Dog){
36. Dog d = (Dog)a;
37. d.eat();
38. }
39. }
40. }
41. }
42.
43. class Animal{}
44.
45. class Dog extends Animal{
46. public void eat(){
47. System.out.println("dog eat");
48. }
49.
50. @Override
51. public String toString() {
52. return "this is a dog";
53. }
54. }
55.
56. class Cat extends Animal{
57. public void move(){
58. System.out.println("cat move");
59. }
60.
61. @Override
62. public String toString() {
63. return "this is a cat";
64. }
65. }
66.
67. /* -------------------- 运行结果 --------------------
68. this is a dog
69. dog eat
70. this is a dog
71. dog eat
72. this is a cat
73. cat move
74. this is a cat
75. cat move
76. -------------------- 运行结果 -------------------- */
1. package com.sust.cst.javase.selflearning.c18_array;
2.
3. /*
4. 方法调用的时候也可以这样传递一个数组
5. */
6. public class Test06 {
7. public static void main(String[] args) {
8.
9. //第一种方式
10. int[] a = {12,3,3425,4,234};
11. m1(a);
12.
13. System.out.println();
14. System.out.println("------------------");
15. System.out.println();
16.
17. //*第二种方式*
18. m1(new int[]{21,3,2412,4,21,324,1});
19. }
20.
21. public static void m1(int[] a) {
22. for (int i = 0; i < a.length; i++)
23. System.out.println(a[i]);
24. }
25. }
26. /* ------------------ 运行结果 ------------------
27. 12
28. 3
29. 3425
30. 4
31. 234
32.
33. ------------------
34.
35. 21
36. 3
37. 2412
38. 4
39. 21
40. 324
41. 1
42.
43. ------------------ 运行结果 ------------------ */
关于main方法中的参数列表 String[] args
- String[] args是专门用来接收命令行参数的
- 例如 java Test07 abc cde fdaf
JVM在调用Test07类的main方法之前,先将” abc cde fdaf”这个字符串以空格的方式分割,然后存储在String数组中
1. package com.sust.cst.javase.selflearning.c18_array;
2.
3. public class Test07 {
4.
5. //main方法中的String[]数组的设计主要是用来接收命令行的参数的
6. public static void main(String[] args) {
7. /*System.out.println("String类型的数组中元素的个数是:" + args.length);
8.
9. //遍历
10. for(int i = 0; i < args.length; i++)
11. System.out.println(args[i]);*/
12.
13. //需求:运行该软件的时候,必须提供用户名和密码
14. //格式:java Test07 username password
15. //如果用户没有提供足够的参数,则退出系统
16.
17. if(args.length != 2){
18. System.out.println("要想使用该系统,必须这样输入:");
19. System.out.println("java Test07 username password");
20. return;
21. }
22. //参数提供正确,如果用户名是admin,密码是123则登录成功
23. String usrname = args[0];
24. String pasword = args[1];
25.
26. //java中比较字符串是否相等,必须使用equals方法
27. //String类型是SUN提供,已经将equals方法重写了,比较的是内容
28. //if(usrname.equals("admin") && pasword.equals("123"))
29. if("admin".equals(usrname) && "123".equals(pasword)){//这种方式可以避免空指针异常
30. System.out.println("登录成功,欢迎" + usrname + "回来");
31. }else{
32. System.out.println("登录失败,用户名" + usrname + "不存在,或密码错误!");
33. }
34.
35. }
36. }
37.
38. /*
39. 在idea中,如何给main方法的参数args赋值?
40. 1.顶边栏选择 Run
41. 2.选择 Edit Confgurations
42. 3.找到 Program arguments,输入所需参数即可。
43. 注意:输入多个参数时,要用空格隔开参数
44. 4.参数配置完成,直接运行即可
45. */
46.
47. /* ------------ 运行结果 ------------
48. 登录成功,欢迎admin回来
49. ------------ 运行结果 ------------ */
关于数组的拷贝
1. package com.sust.cst.javase.selflearning.c18_array;
2.
3. public class Test08 {
4. public static void main(String[] args) {
5. //public static native void arraycopy(Object src, int srcPos,
6. // Object dest, int destPos,
7. // int length);
8. //System.arraycopy(源数组,源数组的开始下标,目标数组,目标数组的开始下标,拷贝的长度);
9.
10. int[] src = {2, 3, 4, 5, 6, 7, 8};
11. int[] dest = {10, 325, 432, 4, 34, 543};
12.
13. /*//把src中的4,5,6拷贝到dest数组中,从4开始
14. System.arraycopy(src, 2, dest, 3, 3);
15.
16. //遍历
17. for (int i = 0; i < dest.length; i++)
18. System.out.println(dest[i]);*/
19.
20. Test08 test08 = new Test08();
21.
22.
23. test08.arrayCopy(test08.a, 2, test08.b, 3, 3);
24. for (int i = 0; i < dest.length; i++)
25. System.out.println(test08.b[i]);
26. }
27.
28. public int[] a = {2, 3, 4, 5, 6, 7, 8};
29. public int[] b = {10, 325, 432, 4, 34, 543};
30.
31. public void arrayCopy(int[] a, int na, int[] b, int nb, int length) {
32. for (int i = nb, j = na; i < nb + length && j < na + length; i++, j++) {
33. b[i] = a[j];
34. }
35. }
36. }
37. /* -------------- 运行结果 --------------
38. 10
39. 325
40. 432
41. 4
42. 5
43. 6
44. -------------- 运行结果 -------------- */
利用数组简单的模拟栈
1. package com.sust.cst.javase.selflearning.c18_array.t04_myStack;
2.
3. public class MyStack {
4. //使用数组存储数据
5. //栈可以存储多个引用类型的元素
6. private Object[] elements;
7.
8. //指向栈顶元素上方的一个帧
9. private int curlen;
10.
11. //栈默认的初始化容量是10
12. //Constructor
13.
14.
15. public MyStack() {
16. this(5);
17. }
18.
19. public MyStack(int max) {
20. elements = new Object[max];
21. curlen = 0;
22. }
23.
24. //栈应该对外提供压栈的方法
25. public void myPush(Object element) throws MyStackOperationException {
26. /*elements[curlen] = element;
27. curlen++;*/
28. if(curlen == elements.length){
29. //异常
30. throw new MyStackOperationException("栈已满");
31. }
32. elements[curlen++] = element;
33. }
34.
35. //栈应该对外提供弹栈的方法
36. public Object myPop() throws MyStackOperationException { //栈顶的元素往外弹
37. /* curlen--;
38. return elements[curlen];*/
39. if(curlen == 0){
40. throw new MyStackOperationException("栈已空");
41. }
42.
43. return elements[--curlen];
44. }
45. }
1. package com.sust.cst.javase.selflearning.c18_array.t04_myStack;
2.
3. public class MyStackOperationException extends Exception {
4. public MyStackOperationException(String message) {
5. super(message);
6. }
7.
8. public MyStackOperationException() {
9. }
10. }
1. package com.sust.cst.javase.selflearning.c18_array.t04_myStack;
2.
3. public class Test {
4. public static void main(String[] args) throws MyStackOperationException {
5. MyStack myStack = new MyStack();
6. User u1 = new User("Jack", 20);
7. User u2 = new User("Jbck", 21);
8. User u3 = new User("Jcck", 22);
9. User u4 = new User("Jdck", 23);
10. User u5 = new User("Jeck", 24);
11.
12. try{
13. myStack.myPush(u1);
14. myStack.myPush(u2);
15. myStack.myPush(u3);
16. myStack.myPush(u4);
17. myStack.myPush(u5);
18.
19. myStack.myPush(u5);
20. }catch (MyStackOperationException e){
21. e.printStackTrace();
22. }
23.
24. try{
25. //弹栈
26. for (int i = 0; i < 5; i++)
27. System.out.println(myStack.myPop());
28.
29. System.out.println(myStack.myPop());
30. }catch (MyStackOperationException e){
31. e.printStackTrace();
32. }
33. }
34. }
35.
36. class User {
37. String name;
38. int age;
39.
40. public User(String name, int age) {
41. this.name = name;
42. this.age = age;
43. }
44.
45. @Override
46. public String toString() {
47. return "User{" +
48. "name='" + name + '\'' +
49. ", age=" + age +
50. '}';
51. }
52. }
53.
54. /* ------------------------------ 运行结果 ------------------------------
55. com.sust.cst.javase.selflearning.c18_array.t04_myStack.MyStackOperationException: 栈已满
56. at com.sust.cst.javase.selflearning.c18_array.t04_myStack.MyStack.myPush(MyStack.java:30)
57. at com.sust.cst.javase.selflearning.c18_array.t04_myStack.Test.main(Test.java:18)
58. User{name='Jeck', age=24}
59. User{name='Jdck', age=23}
60. User{name='Jcck', age=22}
61. User{name='Jbck', age=21}
62. User{name='Jack', age=20}
63. com.sust.cst.javase.selflearning.c18_array.t04_myStack.MyStackOperationException: 栈已空
64. at com.sust.cst.javase.selflearning.c18_array.t04_myStack.MyStack.myPop(MyStack.java:40)
65. at com.sust.cst.javase.selflearning.c18_array.t04_myStack.Test.main(Test.java:27)
66. ------------------------------ 运行结果 ------------------------------ */
二维数组的声明和使用
二维数组特点:
- 二维数组是一个特殊的一维数组
- 特殊的一维数组,特殊在这个一维数组中每一个元素都是“一维数组”
1. package com.sust.cst.javase.selflearning.c18_array.t03_TwoDimensionalArray;
2.
3. public class Test09 {
4.
5. public static void main(String[] args) {
6. //静态初始化二维数组
7. int[][] a = {
8. {1, 2, 3, 4},
9. {2, 34, 23, 532},
10. {3, 4, 54, 23, 523},
11. {332, 242, 676, 6867, 546, 98}
12. };
13.
14. //以上这个数组中有多少个一维数组?
15. System.out.println(a.length + "个一维数组");
16.
17. System.out.println("\n----------------------\n");
18.
19. //获取第一个一维数组
20. int[] a0 = a[0];
21.
22. //获取第一个一维数组中的第一个元素
23. int a00 = a0[0];
24. System.out.println(a00);
25. System.out.println(a[0][0]);
26.
27. System.out.println("\n----------------------\n");
28.
29. //获取最后一个一维数组中最后一个元素
30. System.out.println(a[3][5]);
31. System.out.println(a[a.length - 1][a[a.length - 1].length - 1]);
32.
33. System.out.println("\n----------------------\n");
34.
35. //遍历二维数组
36. for(int i= 0; i< a.length; i++){
37. for(int j = 0; j < a[i].length;j++)
38. System.out.print(a[i][j] + " ");
39. System.out.println();
40. }
41. }
42. }
43.
44. /* ---------------------- 运行结果 ----------------------
45. 4个一维数组
46.
47. ----------------------
48.
49. 1
50. 1
51.
52. ----------------------
53.
54. 98
55. 98
56.
57. ----------------------
58.
59. 1 2 3 4
60. 2 34 23 532
61. 3 4 54 23 523
62. 332 242 676 6867 546 98
63. ---------------------- 运行结果 ---------------------- */
关于二维数组的动态初始化
1. package com.sust.cst.javase.selflearning.c18_array.t03_TwoDimensionalArray;
2.
3. public class Test10 {
4. public static void main(String[] args) {
5.
6. //3个一维数组
7. //每个一维数组中有4个元素
8. int[][] a = new int[3][4];
9.
10. //遍历
11. for(int i = 0; i< a.length;i++) {
12. for (int j = 0; j < a[i].length; j++)
13. System.out.print(a[i][j] + " ");
14.
15. System.out.println();
16. }
17.
18. System.out.println("\n----------------\n");
19.
20. //赋值
21. a[1][2] = 100;
22.
23. //遍历
24. for(int i = 0; i< a.length;i++) {
25. for (int j = 0; j < a[i].length; j++)
26. System.out.print(a[i][j] + " ");
27.
28. System.out.println();
29. }
30. }
31. }
32.
33. /* ---------------- 运行结果 ----------------
34. 0 0 0 0
35. 0 0 0 0
36. 0 0 0 0
37.
38. ----------------
39.
40. 0 0 0 0
41. 0 0 100 0
42. 0 0 0 0
43. ---------------- 运行结果 ---------------- */
1. package com.sust.cst.javase.selflearning.c18_array.t03_TwoDimensionalArray;
2.
3. public class Test11 {
4. public static void main(String[] args) {
5. m1(new int[][]{{1,23,4},{5,6,7,8},{10,9}});
6. }
7.
8. public static void m1(int[][] a){
9. for(int i = 0; i< a.length; i++){
10. for(int j = 0; j < a[i].length;j++)
11. System.out.print(a[i][j] + " ");
12. System.out.println();
13. }
14. }
15. }
16.
17. /* --------- 运行结果 ---------
18. 1 23 4
19. 5 6 7 8
20. 10 9
21. --------- 运行结果 --------- */
数组的排序
冒泡排序算法
1. package com.sust.cst.javase.selflearning.c18_array.t04_sortAndFind;
2.
3. public class BubbleSort {
4. public static void main(String[] args) {
5. int[] a = {3, 1, 6, 2, 5};
6.
7. System.out.println("原始数组:");
8. display(a);
9. bubbleSort(a);
10. System.out.println("排序后的数组:");
11. display(a);
12. }
13.
14. public static int[] bubbleSort(int[] a){
15. for (int i = a.length - 1; i > 0; i--) {
16. for (int j = 0; j < i; j++) {
17. if (a[j] > a[j + 1]) {
18. int temp = a[j];
19. a[j] = a[j + 1];
20. a[j + 1] = temp;
21. }
22. }
23. }
24.
25. return a;
26. }
27.
28. public static void display(int[] a){
29. for (int i = 0; i < a.length; i++)
30. System.out.print(a[i] + " ");
31. System.out.println();
32. }
33. }
34.
35. /* -------------- 运行结果 --------------
36. 原始数组:
37. 3 1 6 2 5
38. 排序后的数组:
39. 1 2 3 5 6
40. -------------- 运行结果 --------------
选择排序算法
找出最小值,然后这个最小值和最前面的数据交换位置
1. package com.sust.cst.javase.selflearning.c18_array.t04_sortAndFind;
2.
3. public class SelectSort {
4. public static void main(String[] args) {
5. int[] a = {3, 1, 6, 2, 5};
6.
7. System.out.println("原始数据为:");
8. display(a);
9. System.out.println("排序后的数据为:");
10. selectSort(a);
11. display(a);
12. }
13.
14. public static void selectSort(int[] a) {
15. for (int i = 0; i < a.length - 1; i++) {
16.
17. //假设第一个数据是最小值
18. //记录最小值元素的下标
19. int min = i;
20.
21. for (int j = i; j < a.length - 1; j++)
22. if (a[min] > a[j + 1])
23. min = j + 1;
24.
25. if (min != i) {
26. int temp = a[i];
27. a[i] = a[min];
28. a[min] = temp;
29. }
30. }
31.
32. }
33.
34. public static void display(int[] a) {
35. for (int i = 0; i < a.length; i++) {
36. System.out.print(a[i] + " ");
37. }
38. System.out.println();
39. }
40. }
41.
42. /* ------------- 运行结果 -------------
43. 原始数据为:
44. 3 1 6 2 5
45. 排序后的数据为:
46. 1 2 3 5 6
47. ------------- 运行结果 ------------- */
数组的查找
二分法查找
二分法查找是建立在已经排序的基础之上的
1. package com.sust.cst.javase.selflearning.c18_array.t04_sortAndFind;
2.
3. import java.util.Scanner;
4.
5. public class DichotomySearch {
6. public static void main(String[] args) {
7.
8. Scanner scanner = new Scanner(System.in);
9. int[] a = {1, 3, 4, 5, 7, 8, 9, 10, 23, 25, 36};
10. System.out.println("请输入要查找的数据:");
11. int destElement = scanner.nextInt();
12.
13. //要求从a数组中查找10这个元素的下标
14. int index = dichotomySearch(a, destElement);//如果找到则返回元素的下标,如果找不到,统一返回-1
15. String searchResult = (index != -1) ? (destElement + "在数组中的下标是:" + index) : ("这个元素不存在");
16.
17. System.out.println(searchResult);
18. }
19.
20. //折半查找
21. public static int dichotomySearch(int[] a, int x) {
22.
23. int index = -1;
24. int begin = 0;
25. int end = a.length - 1;
26.
27. while (begin <= end) {
28.
29. int mid = (begin + end) / 2;
30.
31. if (a[mid] == x) {
32. index = mid;
33. break;
34. }
35. else if (a[mid] > x) {
36. end = mid - 1;
37. } else if (a[mid] < x) {
38. begin = mid + 1;
39. }
40. }
41.
42. return index;
43. }
44. }
45.
46. /* --------------- 运行结果 ---------------
47. 输入数据:
48. 10
49. 运行结果:
50. 请输入要查找的数据:
51. 10
52. 10在数组中的下标是:7
53. 输入数据:
54. 100
55. 运行结果:
56. 请输入要查找的数据:
57. 100
58. 这个元素不存在
59. --------------- 运行结果 --------------- */
Arrays工具类
java.util.Arrays
1. package com.sust.cst.javase.selflearning.c18_array.t04_sortAndFind;
2.
3. import java.util.Arrays;
4. import java.util.List;
5.
6. public class ArraysTest01 {
7. public static void main(String[] args) {
8.
9. int[] a = {3, 1, 6, 4, 7, 5, 3, 2, 8, 10, 123, 43, 5, 34};
10. int[] b = {3, 1, 6, 4, 7, 6, 3, 2, 8, 10, 123};
11.
12. System.out.println("a[] = " + Arrays.toString(a));
13. System.out.println("b[] = " + Arrays.toString(b));
14.
15. int compareIndex = Arrays.compare(a, b);
16. System.out.println(compareIndex);
17.
18. //复制指定的数组,截断或填充零(如果需要),以便副本具有指定的长度。
19. int[] c = Arrays.copyOf(a, 20);
20. System.out.println("c[] = " + Arrays.toString(c));
21. c = Arrays.copyOf(a, 5);
22. System.out.println("c[] = " + Arrays.toString(c));
23.
24. //找到并返回两个数组中第一个不一样的数据的下标
25. int mismatchIndex = Arrays.mismatch(a, b);
26. System.out.println("两个数组中第一个不一样的数据的下标为:" + mismatchIndex);
27.
28. //排序
29. Arrays.sort(a);
30. System.out.println("a[] = " + Arrays.toString(a));
31.
32. //二分法查找
33. System.out.println();
34. int index = Arrays.binarySearch(a, 2);
35. System.out.println(2+"的下标为:"+index);
36.
37. //将第3位开始,第4位除外的数据改写为99
38. System.out.println();
39. Arrays.fill(a, 3,4,99);
40. System.out.println("a[] = " + Arrays.toString(a));
41. }
42. }
43.
44. /* ------------------------------ 运行结果 ------------------------------
45. a[] = [3, 1, 6, 4, 7, 5, 3, 2, 8, 10, 123, 43, 5, 34]
46. b[] = [3, 1, 6, 4, 7, 6, 3, 2, 8, 10, 123]
47. -1
48. c[] = [3, 1, 6, 4, 7, 5, 3, 2, 8, 10, 123, 43, 5, 34, 0, 0, 0, 0, 0, 0]
49. c[] = [3, 1, 6, 4, 7]
50. 两个数组中第一个不一样的数据的下标为:5
51. a[] = [1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 10, 34, 43, 123]
52.
53. 2的下标为:1
54.
55. a[] = [1, 2, 3, 99, 4, 5, 5, 6, 7, 8, 10, 34, 43, 123]
56. ------------------------------ 运行结果 ------------------------------ */
常用类
String
String类是不可变类,也就是说String对象声明后,将不可修改。
java.lang.String;是字符串类型
- 字符串一旦创建不可再改变,”abc”字符串对象一旦创建,不可再改变成”abcd”.
- 提升字符串的访问效率,在程序中使用了“缓存“技术”。所以,在java中所有使用“双引号”括起来的字符串都会在“字符串常量池”中创建一份,字符串常量池在方法区中被存储。
- 在程序执行过程中,如果程序用到某个字符串,例如”abc”,那么程序会在字符串常量池中去搜索该字符串,如果没有找到则在字符串常量池中新建一个”abc”字符串,如果找到就直接拿过来用。(字符串常量池是一个缓存区,为了提高访问字符串的效率)
1. package com.sust.cst.javase.selflearning.c19_commonclass.t01_String;
2.
3. public class Test01 {
4. public static void main(String[] args) {
5.
6. //创建一个"abc"字符串对象,该对象的内存地址,让s1变量保存
7. //s1是一个引用,s1指向"abc"对象
8. String s1 = "abc";
9.
10. //可以让s1重新指向吗?
11. //可以,s1是局部变量,s1前边没有final,所以s1可以重新指向
12. //但是"def"字符串本身不可变
13. s1 = "def";
14.
15. String s2 = "hello";//在字符串常量池中新建一个"hello"字符串对象,该对象不可变
16. String s3 = "hello";//从字符串常量池中直接拿来用
17. System.out.println(s2 == s3); //true
18.
19. //比较两个字符串是否相等,不能用"=="
20. String s4 = new String("abc");
21. String s5 = new String("abc");
22.
23. //new 关键字一定是在堆中开辟空间,所以两个字符串的内存地址不相等
24. System.out.println(s4 == s5); //false
25.
26. //比较两个字符串是否一致,必须使用String类提供的equals方法
27. System.out.println(s4.equals(s5)); //true
28.
29. //以下程序执行,会在字符串常量池中创建3个字符串对象
30. //"aaa" "bbb" "aaabbb"
31. String s6 = "aaa";
32. String s7 = "bbb";
33. String s8 = s6 + s7;
34. }
35. }
36. /* ------------ 运行结果 ------------
37. true
38. false
39. true
40. ------------ 运行结果 ------------ */
1. package com.sust.cst.javase.selflearning.c19_commonclass.t01_String;
2.
3. /*
4. 分析以下程序创建字符串对象的区别
5. 1.String s1 = "abc"; 只会在字符串常量池中创建一个"abc"字符串对象
6.
7. 2.String s2 = new String("hello"); 会在字符串常量池中创建一个"hello"字符串对象,并且会在堆中再创建一个字符串对象
8.
9. 第二种方式比较浪费内存,常用的是第一种方式
10. */
11.
12. public class Test02 {
13. public static void main(String[] args) {
14.
15. //推荐使用这种方式
16. String s1 = "abc";
17.
18. //不推荐使用这种方式,它不仅会在字符串常量池中创建对象,还会在堆中创建对象,比较浪费空间
19. String s2 = new String("abc");
20. }
21. }
使用String的时候我们应该注意的问题,尽量不要做字符串频繁的拼接操作。因为字符串一旦创建不可改变,只要频繁拼接,就会在字符串常量池中创建大量的字符串对象,给垃圾回收带来问题。
1. package com.sust.cst.javase.selflearning.c19_commonclass.t01_String;
2.
3. public class Test03 {
4. public static void main(String[] args) {
5.
6. //判断以下程序创建了几个对象?
7. //堆中2个
8. //方法区中字符串常量池中1个
9. String s1 = new String("hello");
10. String s2 = new String("hello");
11. }
12. }
1. package com.sust.cst.javase.selflearning.c19_commonclass.t01_String;
2.
3. public class Test04 {
4. public static void main(String[] args) {
5.
6. String[] ins = {"sport", "music", "food", "sleep"};
7.
8. //要求将上面的兴趣爱好凭借成一个字符串"sport,music,food,sleep"
9. String temp = "";
10.
11. //不太推荐以下方式,这种方式频繁的拼接字符串,会对垃圾回收产生一些问题
12. for (int i = 0; i < ins.length; i++) {
13. temp += ins[i];
14.
15. if (i < ins.length - 1)
16. temp += ",";
17. }
18.
19. System.out.println(temp);
20. }
21. }
22. /* ----------- 运行结果 -----------
23. sport,music,food,sleep
24. ----------- 运行结果 ----------- */
关于字符串常用构造方法
1. package com.sust.cst.javase.selflearning.c19_commonclass.t01_String;
2.
3. public class Test05 {
4. public static void main(String[] args) {
5.
6. //1.
7. String s1 = "abc";
8.
9. //2.
10. String s2 = new String("abc");
11.
12. //3.
13. byte[] bytes = {97, 98, 99, 100};
14. String s3 = new String(bytes);
15. System.out.println(s3);//abcd String已经重写了Object中的String
16.
17. //4.
18. String s4 = new String(bytes, 1, 2);
19. System.out.println(s4);//bc
20.
21. //5.
22. char[] c1 = {'我','是','中','国','人'};
23. String s5 = new String(c1);
24. System.out.println(s5);//我是中国人
25.
26. //6.
27. String s6 = new String(c1,2,2);
28. System.out.println(s6);//中国
29. }
30. }
31. /* ---------- 运行结果 ----------
32. abcd
33. bc
34. 我是中国人
35. 中国
36. ---------- 运行结果 ---------- */
字符串常用的方法
1. package com.sust.cst.javase.selflearning.c19_commonclass.t01_String;
2.
3. public class Test06 {
4. public static void main(String[] args) {
5.
6. //1. char charAt(int index); 返回指定索引处的char值
7. String s1 = "我是xx,是xx";
8. char c1 = s1.charAt(2);
9. System.out.println(c1);//王
10.
11. //2. boolean endsWith(String suffix); 测试此字符串是否以指定的后缀结束
12. System.out.println("helloWorld.java".endsWith("java"));//true
13. System.out.println("helloWorld.java".endsWith(".java"));//true
14. System.out.println("helloWorld.java".endsWith("helloWorld.java"));//true
15.
16. System.out.println("helloWorld.java".endsWith("helloWorld.txt"));//false
17. System.out.println("helloWorld.java".endsWith("java "));//false
18.
19. //3. boolean equalsIgnoreCase(String anotherString); 将此String与另一个String比较,不考虑大小写
20. System.out.println("abc".equalsIgnoreCase("aBC"));//true
21.
22. //4. byte[] getBytes(); 使用平台默认字符集将此String编码到byte序列,并将结果存储到新的byte数组
23. byte[] bytes = "abc".getBytes();
24. for (int i = 0; i < bytes.length; i++) {
25. System.out.print(bytes[i] + " ");// 97 98 99
26. }
27. System.out.println();
28.
29. //5. int indexOf(String str) 返回指定字符串在此字符串中第一次出现出的索引
30. System.out.println("http://192.168.1.100.8080/oa/login.action?username=jack&pwd=123".indexOf("/oa"));//25
31.
32. //6. int indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定索引开始
33. System.out.println("javaoraclec++javavb".indexOf("java", 1));//13
34.
35. //7. int lastIndexOf(String str) 返回指定字符串中最右边出现处的索引
36. System.out.println("javaoraclec++javavb".lastIndexOf("java"));//13
37.
38. //8. int lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后依次出现处的索引,从指定的索引开始反向搜索
39. System.out.println("javaoraclec++javavb".lastIndexOf("java", 14));//13
40.
41. //9. int length(); 返回字符串长度
42. System.out.println("abc".length());//3 数组是length属性,String是length()方法
43.
44. //10. String replaceAll(String regex, String replacement)
45. //使用指定的字面值替换序列替换此字符串所有匹配给定的正则表达式的子字符串
46. System.out.println("javaoraclec++javavb".replaceAll("java", "mysql"));//这个程序是4个字符串
47. //
48.
49. //11. String[] split(String regex)
50. //根据给定正则表达式的匹配拆分此字符串
51. String myTime = "2008,08,08";
52. String[] ymd = myTime.split(",");
53. for (int i = 0; i < ymd.length; i++) {
54. System.out.print(ymd[i]);
55. }
56. System.out.println();
57.
58. //12.boolean startWith(String s); 判断字符串以s字符串开始
59. System.out.println("/system/login.action".startsWith("/"));//true
60.
61. //13.String substring(int begin); 从begin开始截取字符串
62. System.out.println("/oa/login.action".substring(3));// /login.action
63.
64. //14. String substring(int beginIndex, int endIndex) 从beginIndex到endIndex(包含bginIndex,不包括endIndex)截取字符串
65. System.out.println("/oa/login.action".substring(4, 9));// login
66.
67. //15. char[] toCharArray(); 将字符串转换成char数组
68. char[] c2 = "我是刘洋".toCharArray();
69. for(int i = 0; i<c2.length;i++)
70. System.out.print(c2[i] + " ");
71. System.out.println();
72.
73. //16. String toUpperCase() 转换成大写
74. System.out.println("AbCdef".toUpperCase());
75.
76. //17. String toLowerCase() 转换成小写
77. System.out.println("ABCdEf".toLowerCase());
78.
79. //18. String trim() 去除字符串开头和结尾的空白
80. System.out.print(" a b c d e ".trim());
81. System.out.println("Test");
82.
83. //19. String.valueOf(char[] data) 将其他类型的数据转换为字符串类型
84. //String.valueOf(Object obj);
85. Object o = null;
86. System.out.println(o);//不会,因为并不是直接调用toString方法,String valueOf(Ojbect)这个方法对空值进行处理了
87. System.out.println(String.valueOf(o));
88. //System.out.println(o.toString()); 会出现空指针异常
89. }
90. }
91.
92. /* --------------- 运行结果 ---------------
93. x
94. true
95. true
96. true
97. false
98. false
99. true
100. 97 98 99
101. 25
102. 13
103. 13
104. 13
105. 3
106. mysqloraclec++mysqlvb
107. 20080808
108. true
109. /login.action
110. login
111. 我 是 刘 洋
112. ABCDEF
113. abcdef
114. a b c d e
115. --------------- 运行结果 --------------- */
正则表达式
- 正则表达式是一门独立的学科
- 是一种字符模型,专门做字符串格式匹配的
- 正则表达式是通用的
例如:正则表达式”^a{2}$”表示2个a字符,等同于”aa”
\d 数字
\D 非数字
\w 英文字母
\W 非英文字母
1. package com.sust.cst.javase.selflearning.c19_commonclass.t01_String;
2.
3. /*
4. 正则表达式
5. */
6. public class Test07 {
7. public static void main(String[] args) {
8.
9. System.out.println("aa".matches("a{2}$"));//true
10. System.out.println("ab".matches("a{2}$"));//false
11.
12. String s1 = "asdd33dfsdaf33ddsd55fdd3dssf434sdf455ddsdddh565gggh55ddhg";
13.
14. //将dd替换为"中"
15. System.out.println(s1.replaceAll("dd","中"));
16.
17. //将dd替换为"中"
18. System.out.println(s1.replaceAll("d{2}","中"));
19.
20. //将数字替换为"中"
21. System.out.println(s1.replaceAll("\\d", "中"));
22.
23. //将非数字替换为"中"
24. System.out.println(s1.replaceAll("\\D", "中"));
25. }
26. }
27. /* ---------------------------------- 运行结果 ----------------------------------
28. true
29. as中33dfsdaf33中sd55f中3dssf434sdf455中s中dh565gggh55中hg
30. as中33dfsdaf33中sd55f中3dssf434sdf455中s中dh565gggh55中hg
31. asdd中中dfsdaf中中ddsd中中fdd中dssf中中中sdf中中中ddsdddh中中中gggh中中ddhg
32. 中中中中33中中中中中中33中中中中55中中中3中中中中434中中中455中中中中中中中565中中中中55中中中中
33. ---------------------------------- 运行结果 ---------------------------------- */
StringBuffer和StringBuilder
StringBuffer和StringBuilder是什么?
是一个字符串缓冲区,
工作原理
预先在内存中申请一块空间,以容纳字符序列
如果预留的空间不够用,则进行自动扩容,以容纳更多的字符序列。
StringBuffer, StringBuilder和String最大的区别?
String是不可变的字符序列,存储在字符串常量池中;
StringBuffer是一个char数组,但是该char数组是可变的,并且可以自动扩容。
StringBuffer和StringBuilder的默认初始化容量是16
如何优化StringBuffer和StringBuilder?
最好在创建StringBuffer之前,预测StringBuffer的存储字符数量。然后在创建StringBuffer的时候采用指定初始化榕江的方式创建StringBuffer.为了减少底层数组的拷贝,提高效率。
1. package com.sust.cst.javase.selflearning.c19_commonclass.t02_StringBufferAndStringbuilder;
2.
3. /*
4. java.lang.StringBuffer;
5. java.lang.StringBuilder;
6. */
7.
8. public class Test01 {
9. public static void main(String[] args) {
10.
11.
12. //创建字符串缓冲区对象
13. StringBuffer sb = new StringBuffer();//默认初始化值为16
14.
15. //可以向StringBuffer中追加字符串
16. String[] ins = {"体育", "音乐", "睡觉", "旅游"};
17.
18. //推荐字符串频繁拼接使用StringBuffer或StringBuilder
19. for(int i =0 ; i < ins.length;i++){
20. sb.append(ins[i]);
21.
22. if(i < ins.length-1)
23. sb.append(",");
24. }
25.
26. System.out.println(sb);
27. }
28. }
29. /* ------------- 运行结果 -------------
30. 体育,音乐,睡觉,旅游
31. ------------- 运行结果 ------------- */
StringBuffer和StringBuilder的区别?
StringBuffer是线程安全的,可以在多线程的环境下使用不会出现问题
StringBuidler是非线程安全的,在多线程环境下使用可能出现问题
基本数据类型对应的8个包装类
基本数据类型与其包装类型
基本数据类型 | 包装类型 |
byte | java.lang.Byte; |
short | java.lang.Short; |
int | java.lang.Integer; |
long | java.lang.Long; |
float | java.lang.Float; |
double | java.lang.Double; |
boolean | java.lang.Boolean; |
char | java.lang.Character; |
思考:java中提供的8种数据类型不够用吗?为什么java中还需要提供对应的包装类呢?
方便
1. package com.sust.cst.javase.selflearning.c19_commonclass.t03_thePackageTypeOfTheBasicDataType.m01_Integer;
2.
3. public class Test01 {
4. //需求:规定m1方法可以接收java中任何一种数据类型
5. //m1方法如果想接收byte类型的数据,可以将byte类型先包装成java.lang.Byte;再传递参数
6. public static void m1(Object o){
7. System.out.println(o);
8. }
9.
10. public static void main(String[] args) {
11. byte b = 10;
12.
13. Byte b1 = new Byte(b);
14.
15. m1(b1);//10 Byte已经将Object中的toString方法重写
16. }
17. }
18. /* --------- 运行结果 ---------
19. 10
20. --------- 运行结果 --------- */
继承结构
以java.lang.Integer类型为例,讲解8种类型
1. package com.sust.cst.javase.selflearning.c19_commonclass.t03_thePackageTypeOfTheBasicDataType.m01_Integer;
2.
3. /*
4. 以java.lang.Integer;类型为例,讲解8种类型
5. */
6. public class Test02 {
7. public static void main(String[] args) {
8.
9. //获取int类型的最大值和最小值
10. System.out.println("int 类型最小值:" + Integer.MIN_VALUE);
11. System.out.println("int 类型最大值:" + Integer.MAX_VALUE);
12.
13. //获取byte类型的最大值和最小值
14. System.out.println("byte 类型最小值:" + Byte.MIN_VALUE);
15. System.out.println("byte 类型最大值:" + Byte.MAX_VALUE);
16.
17. //创建Integer类型的对象
18. Integer x1 = new Integer(10);
19. Integer x2 = new Integer("123");
20. System.out.println(x1); //10
21. System.out.println(x2); //123
22.
23. //以下程序编译可以通过
24. //但是运行的时候会报异常,数字格式化异常 NumberFormatException
25. //虽然可以将字符串转换为Integer类型,但是该字符串也必须是"数字字符串"
26. //Integer x3 = new Integer("abc"); //NumberFormatException
27. }
28. }
29. /* ----------------------------- 运行结果 -----------------------------
30. int 类型最小值:-2147483648
31. int 类型最大值:2147483647
32. byte 类型最小值:-128
33. byte 类型最大值:127
34. 10
35. 123
36. Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
37. at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
38. at java.base/java.lang.Integer.parseInt(Integer.java:658)
39. at java.base/java.lang.Integer.<init>(Integer.java:1117)
40. at com.sust.cst.javase.selflearning.c19_commonclass.t03_thePackageTypeOfTheBasicDataType.m01_Integer.Test02.main(Test02.java:24)
41. ----------------------------- 运行结果 ----------------------------- */
关于Integer中常用的方法
1. package com.sust.cst.javase.selflearning.c19_commonclass.t03_thePackageTypeOfTheBasicDataType.m01_Integer;
2.
3. /*
4. 关于Integer中常用的方法
5. */
6.
7. public class Test03 {
8. public static void main(String[] args) {
9.
10. //int --> Integer
11. //基本数据类型 --> 引用数据类型
12. Integer i1 = new Integer(10);
13.
14. //int intValue() 以int类型返回该Integer的值
15. //Integer --> int
16. //引用类型 --> 基本数据类型
17. int i2 = i1.intValue();
18.
19. System.out.println(i2 + 1);//11
20.
21. //重要!!!static int parseInt(String a) 将字符串参数作为有符号的十进制整数进行解析
22. //字符串转换为整形数字
23. int age = Integer.parseInt("26");
24. System.out.println(age+1);//27
25.
26. //"abc"字符串必须是数字字符串才行
27. //NumberFormatException
28. //int price = Integer.parseInt("abc");
29.
30. //重要!!!static double parseDouble(String a)
31. //字符串转换为double数字
32. double price = Double.parseDouble("3.12");
33. System.out.println(price+1.0);//4.12
34.
35. //static String toBinaryString(int i) 十进制转换为二进制
36. String s1 = Integer.toBinaryString(10);
37. System.out.println(s1);//1010
38.
39. //static String toHexString(int i) 十进制转换为十六进制
40. String s2 = Integer.toHexString(10);
41. System.out.println(s2);//a
42. //static String toOctalString(int i) 十进制转换为八进制
43. String s3 = Integer.toOctalString(10);
44. System.out.println(s3);//12
45.
46. //static Integer valueOf(int i) 将int 类型转换成Integer
47. Integer x1 = Integer.valueOf(10);
48. //static Integer valueOf(String s) 将String 类型转换成Integer
49. Integer x2 = Integer.valueOf("10");
50. }
51. }
52. /* ---------------------------- 运行结果 ----------------------------
53. 11
54. 27
55. 4.12
56. 1010
57. a
58. 12
59. ---------------------------- 运行结果 ---------------------------- */
Integer int String 三种类型相互转换
1. package com.sust.cst.javase.selflearning.c19_commonclass.t03_thePackageTypeOfTheBasicDataType.m01_Integer;
2.
3. /*
4. Integer
5. int
6. String
7. 三种类型相互转换
8. */
9. public class Test04 {
10. public static void main(String[] args) {
11. //1.int --> Integer
12. Integer i1 = Integer.valueOf(10);
13.
14. //2.Integer --> int
15. int i2 = i1.intValue();
16.
17. //3.String --> Integer
18. Integer i3 = Integer.valueOf("10");
19.
20. //4.Integer --> String
21. String s1 = i3.toString();
22.
23. //5.String --> int
24. int i = Integer.parseInt("123");
25.
26. //6.int --> String
27. String s2 = 10 + "";
28. }
29. }
JDK5.0新特性
以下的特性适合JDK1.5之后的,包括1.5
JDK1.4,包括1.4在内,所有之前的版本不能使用以下特性
自动装箱(auto_boxing)和自动拆箱(auto_unboxing)
1. package com.sust.cst.javase.selflearning.c19_commonclass.t03_thePackageTypeOfTheBasicDataType.m01_Integer;
2.
3. public class Test05 {
4. public static void main(String[] args) {
5. //JDK5.0之前的
6. //int --> Integer(装箱)
7. Integer i1 = new Integer(10);
8.
9. //Integer --> int (拆箱)
10. int i2 = i1.intValue();
11.
12. //JDK5.0之后
13. Integer i3 = 10;//自动装箱
14. int i4 = i3;//自动拆箱
15.
16. System.out.println(i3);//"10"
17. System.out.println(i4+1);//11
18.
19. m1(10);//自动装箱
20.
21. System.out.println(m2(10, 5) + 1);//自动装箱
22. }
23.
24. public static void m1(Object o){
25. System.out.println(o);
26. }
27.
28. public static int m2(Integer i1, Integer i2){
29. return i1 - i2; //自动拆箱
30. }
31. }
32. /* ----------------- 运行结果 -----------------
33. 10
34. 11
35. 10
36. 6
37. ----------------- 运行结果 ----------------- */
深入自动装箱和自动拆箱
- 自动装箱和自动拆箱是程序编译阶段的一个概念,和程序运行无关
- 自动装箱和自动拆箱主要目的是方便程序员编码
1. package com.sust.cst.javase.selflearning.c19_commonclass.t03_thePackageTypeOfTheBasicDataType;
2.
3. /*
4. 深入自动装箱和自动拆箱
5. */
6. public class Test06 {
7. public static void main(String[] args) {
8.
9. Integer i1 = new Integer(10);
10. Integer i2 = new Integer(10);
11.
12. //这里不会有自动拆箱
13. System.out.println(i1 == i2); //fasle 这里比较的是i1和i2的内存地址
14.
15. //比较2个Integer类型的数据是否相等,不能用"=="
16. //Integer已经重写了Object中的equals方法
17. System.out.println(i1.equals(i2)); //true
18.
19. //重点:
20. Integer i3 = 128;
21. Integer i4 = 128;
22.
23. //上面等同于
24. //Integer i3 = new Integer(128);
25. //Integer i4 = new Integer(128);
26.
27. System.out.println(i3 == i4);//false
28.
29. //注意以下程序
30. //如果x∈[-128 - 127],java中引入了一个"整型常量池",在方法区中
31. //该整型常量池值存储[-128,127]中的数据
32.
33. Integer i5 = 127; //这个程序不会在堆中创建对象,会直接从整型常量池中拿
34. Integer i6 = 127;
35.
36. System.out.println(i5 == i6);//true
37.
38. Integer i7 = -128;
39. Integer i8 = -128;
40. System.out.println(i7 == i8);//true
41.
42. Integer i9 = -129;
43. Integer i10 = -129;
44. System.out.println(i9 == i10);//false
45. }
46. }
47. /* ---------------------- 运行结果 ----------------------
48. false
49. true
50. false
51. true
52. true
53. false
54. ---------------------- 运行结果 ---------------------- */
日期相关类
获取自1970年1月1日 00时00分00秒 000毫秒 到当前的毫秒数
获取系统当前时间
格式化日期
1. package com.sust.cst.javase.selflearning.c19_commonclass.t04_Data;
2.
3. import java.text.SimpleDateFormat;
4. import java.util.Date;
5.
6. public class Test01 {
7. public static void main(String[] args) {
8.
9. /*
10. 获取自1970年1月1日 00时00分00秒 000毫秒 到当前的毫秒数
11.
12. 1000毫秒 == 1秒
13. */
14.
15. long now = System.currentTimeMillis();
16. System.out.println(now);//1573180904328
17.
18. /*
19. 获取系统当前时间
20. */
21. Date nowTime = new Date();
22. System.out.println(nowTime);//Fri Nov 08 10:45:20 CST 2019
23.
24. //以上程序说明java.util.Date已经重写了Object中的toString方法
25. //只不过重写的结果对中国人而言不太容易理解
26.
27. //所以引入格式化日期
28. //java.util.Date; --> String
29.
30. /*
31. 日期格式:
32. y 年
33. M 月
34. d 日
35. H 小时
36. m 分
37. s 秒
38. S 毫秒
39. */
40. //1.创建日期格式化对象
41. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss SSS");
42. //2.开始格式化(Date --> String)
43. String strTime = simpleDateFormat.format(nowTime);
44.
45. System.out.println(strTime); //2019年11月08日 10:59:00 774
46. }
47. }
48. /* --------------------- 运行结果 ---------------------
49. 1573182073362
50. Fri Nov 08 11:01:13 CST 2019
51. 2019年11月08日 11:01:13 363
52. --------------------- 运行结果 --------------------- */
String => Date
获取特殊日期
1. package com.sust.cst.javase.selflearning.c19_commonclass.t04_Data;
2.
3. /*
4. 获取特定日期
5. */
6.
7. import java.text.ParseException;
8. import java.util.Date;
9.
10. import java.text.SimpleDateFormat;
11. public class Test02 {
12. public static void main(String[] args) throws ParseException {
13.
14. String strTime = "2008年08月08日 08:08:08 888";
15.
16. //将String日期转换冲鞥日期类型Date
17. //String --> Date
18.
19. //1.创建日期格式化对象
20. //格式不饿能随便写,应该设上面的字符串格式相同
21. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss SSS");
22.
23. //2.将字符串转换成日期类型
24. Date time = simpleDateFormat.parse(strTime);
25.
26. System.out.println(time); //Fri Aug 08 08:08:08 CST 2008
27. }
28. }
29. /* -------------- 运行结果 --------------
30. Fri Aug 08 08:08:08 CST 2008
31. -------------- 运行结果 -------------- */
Data构造方法加参数
1. package com.sust.cst.javase.selflearning.c19_commonclass.t04_Data;
2.
3. import java.text.SimpleDateFormat;
4. import java.util.Date;
5.
6. /*
7. Date t = Date(long date)
8. */
9. public class Test03 {
10. public static void main(String[] args) {
11. Date date = new Date(1000);
12.
13. //date --> String
14. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy,MM,dd HH:mm:ss SSS");
15.
16. //北京东八区
17. //1970年1月1日 08时00分01秒 000
18. System.out.println(simpleDateFormat.format(date));//1970,01,01 08:00:01 000
19.
20. //获取当前系统时间的前十分钟时间
21. Date date2 = new Date((System.currentTimeMillis() - 10 * 60 * 1000));
22. System.out.println(simpleDateFormat.format(date2));
23. System.out.println(simpleDateFormat.format(new Date()));
24. }
25. }
26. /* ---------------------- 运行结果 ----------------------
27. 1970,01,01 08:00:01 000
28. 2019,11,15 10:00:47 272
29. 2019,11,15 10:10:47 272
30. ---------------------- 运行结果 ---------------------- */
日历 Calendar
1. package com.sust.cst.javase.selflearning.c19_commonclass.t04_Data;
2. import java.text.ParseException;
3. import java.text.SimpleDateFormat;
4. import java.util.Calendar;
5. import java.util.Date;
6. /*
7. 日历 Calendar
8. */
9. public class Test04 {
10. public static void main(String[] args) throws ParseException {
11. //获取系统当前日历 Calendar
12. //static Claendar getInstance() 使用默认时区和语言环境获得一个日历
13. Calendar calendar = Calendar.getInstance();
14. //查看当前日历的“星期几”
15. //int get(int field) 返回给定日历字段的值
16. int x = calendar.get(Calendar.DAY_OF_WEEK);
17. /*
18. public static final int DAY_OF_MONTH = 5;
19. public static final int DAY_OF_YEAR = 6;
20. public static final int DAY_OF_WEEK = 7;
21. */
22. System.out.println(x);//6(星期日为第一天)
23. System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//15
24.
25. //获取2008年8月8日是星期几
26. //1.获取2008年8月8日的日历
27. String strTime = "2008,08,08";
28. Date date = new SimpleDateFormat("yyyy,MM,dd").parse(strTime);
29. calendar.setTime(date);
30. //2.获取星期几
31. System.out.println(calendar.get(Calendar.DAY_OF_WEEK));//6 星期五
32. }
33. }
34. /* ------- 运行结果 -------
35. 6
36. 15
37. 6
38. ------- 运行结果 ------- */
数字相关类
DecimalFormat
数字格式元素:
- # 任意数字
- , 千分位
- . 小数点
- 0不够补0
1. package com.sust.cst.javase.selflearning.c19_commonclass.t05_num;
2.
3. import java.text.DecimalFormat;
4.
5. /*
6. 关于数字格式化 java.text.DecimalFormat;
7. */
8. public class Test01 {
9. public static void main(String[] args) {
10.
11. //1.创建数字格式化对象
12. //需求:加入千分位。
13. DecimalFormat decimalFormat = new DecimalFormat("###,###");
14.
15. //2.开始格式化
16. //Number-->String
17. System.out.println(decimalFormat.format(1234567));//"1,234,567"
18.
19. //加入千分位,保留2位小数
20. decimalFormat = new DecimalFormat("###,###.##");
21. System.out.println(decimalFormat.format(1234567.128));//"1,234,567.13"
22.
23. //加入千分位,保留4位小数,不够补0
24. decimalFormat = new DecimalFormat("###,###.0000");
25. System.out.println(decimalFormat.format(1234567.128));//"1,234,567.1280"
26. }
27. }
28. /* ---------------- 运行结果 ----------------
29. 1,234,567
30. 1,234,567.13
31. 1,234,567.1280
32. ---------------- 运行结果 ---------------- */
BigDecimal
该类型数据精确度极高,适合做财务软件
财务软件中double类型精确度太低
1. package com.sust.cst.javase.selflearning.c19_commonclass.t05_num;
2.
3. import java.math.BigDecimal;
4.
5. /*
6. java.math.BigDecimal;
7. */
8. public class Test02 {
9. public static void main(String[] args) {
10.
11. //创建大数据
12. BigDecimal b1 = new BigDecimal(10);
13. BigDecimal b2 = new BigDecimal(20);
14.
15. //做加法运算
16. //b1 + b2//错误:两个引用类型不能做加法运算
17.
18. //必须调用方法
19. //BigDecimal add(BigDecimal augend)
20. //返回一个BigDecimal,其值为(this + augend),其标度为max(this.scale(), augend.scale())
21. BigDecimal b3 = b1.add(b2);
22. System.out.println(b3);
23. }
24. }
25. /* ------------ 运行结果 ------------
26. 30
27. ------------ 运行结果 ------------ */
Random
1. package com.sust.cst.javase.selflearning.c19_commonclass.t06_random;
2.
3. import java.util.Random;
4.
5. /*
6. 生成随机数
7. */
8. public class Test01 {
9. public static void main(String[] args) {
10. //创建一个新的随机数生成器
11. Random random = new Random();
12.
13. //生成int 类型的随机数
14. //int nextInt(int n)
15. // 返回一个伪随机数,
16. // 它是取自随机数生成器序列的,在0(包括)和指定值(不包括)之间均匀分布的int值
17. int x = random.nextInt(101);//0-100之间的随机数
18. System.out.println(x);
19.
20. //循环生成5个0-100之间的随机数
21. for (int i = 0; i < 5; i++) {
22. System.out.print(random.nextInt(101) + " ");
23. }
24. System.out.println();
25.
26. //生成5个不重复的随机数
27. int[] temp = new int[5];
28. int i = 0;
29. while (i < 5) {
30. temp[i] = random.nextInt(101);
31. for (int j = 0; j < i; j++) {
32. if (temp[i] == temp[j]) {
33. i--;
34. break;
35. }
36. }
37. i++;
38. }
39.
40. for (i = 0; i < temp.length; i++)
41. System.out.print(temp[i] + " ");
42. System.out.println();
43. }
44. }
45. /* ----------------- 运行结果 -----------------
46. 100
47. 81 54 79 84 55
48. 68 96 67 77 8
49. ----------------- 运行结果 ----------------- */
枚举 Enum
不使用枚举会造成问题
1. package com.sust.cst.javase.selflearning.c19_commonclass.t07_enum;
2. /*
3. 定义一个方法,该方法的作用是计算两个int类型的商
4. 如果计算成功,则该方法返回1;如果执行失败,则该方法返回0
5. */
6. public class Test01 {
7. public static void main(String[] args) {
8. int a = 10;
9. int b = 0;
10. System.out.println("计算" + a + " \\ " + b + "的商:");
11. int retValue = divide(a, b);
12.
13. if(retValue == 0)
14. System.out.println("失败");
15. else if(retValue == 1)
16. System.out.println("成功");
17. }
18.
19. //程序执行成功,但是该程序存在风险
20. //程序中的问题能在编译阶段解决的绝对不会放在运行期解决
21. //所以以下程序可以引入枚举类型enum
22. public static int divide(int a, int b){
23. int result = 1;
24.
25. try{
26. int c = a/b;
27. }catch (Exception e){
28. result = 10;
29. }
30.
31. return result;
32. }
33. }
34. /* ------- 运行结果 -------
35. 计算10 \ 0的商:
36. 无输出,程序编写错误
37. ------- 运行结果 ------- */
使用枚举带来的好处
1. package com.sust.cst.javase.selflearning.c19_commonclass.t07_enum;
2.
3. public class Test02 {
4. public static void main(String[] args) {
5. int a = 10;
6. int b = 0;
7. System.out.println("计算" + a + " \\ " + b + "的商:");
8. Result retValue = divide(a, b);
9.
10. if (retValue == Result.FAIL)
11. System.out.println("失败");
12. else if (retValue == Result.SUCCESS)
13. System.out.println("成功");
14. }
15.
16. //程序执行成功,但是该程序存在风险
17. //程序中的问题能在编译阶段解决的绝对不会放在运行期解决
18. //所以以下程序可以引入枚举类型enum
19. public static Result divide(int a, int b) {
20. Result result = Result.SUCCESS;
21.
22. try {
23. int c = a / b;
24. } catch (Exception e) {
25. result = Result.FAIL;
26. }
27.
28. return result;
29. }
30. }
31.
32. //定义一个枚举类型
33. enum Result {
34. //规范要求:大写
35. SUCCESS, FAIL //有限的
36. }
37.
38. //四季
39. enum Season {
40. SPRING, SUMMER, AUTUMN, WINTER
41. }
42.
43. /* -------- 运行结果 --------
44. 计算10 \ 0的商:
45. 失败
46. -------- 运行结果 -------- */
集合
集合继承结构图
UML图例:
- 实线空心箭头 :继承关系,箭头指向父类
- 虚线实心箭头 :依赖关系,箭头指向被依赖的对象
- 虚线空心箭头 :实现关系,箭头指向被实现的接口
Collection继承结构图
单向链表
双向链表
Map继承结构图
Collecton类中常用方法
boolean add(Object), void clear(), boolean isEmpty()
boolean add(Object element); 向集合中添加元素
void clear(); 清空集合
boolean isEmpty(); 判断集合中是否有元素
int size(); 获取集合中元素的个数
1. package com.sust.cst.javase.selflearning.c20_Collection.t01_Collection;
2.
3. import java.util.ArrayList;
4. import java.util.Collection;
5.
6. /*
7. boolean add(Object element); 向集合中添加元素
8. void clear(); 清空集合
9. boolean contains(Object element); 判断集合中是否包含某个元素
10. boolean isEmpty(); 判断集合中是否有元素
11. Iterator iterator(); 获取集合所依赖的迭代器对象
12. boolean remove(Object o); 删除集合中某个元素
13. int size(); 获取集合中元素的个数
14. Object[] toArray(); 将集合转换为数组
15. */
16. public class Test01 {
17. public static void main(String[] args) {
18. //1.创建集合
19. Collection c = new ArrayList();//多态
20.
21. //2.添加元素
22. c.add(1);//自动装箱
23. c.add(new Integer(100));
24.
25. Object o = new Object();
26. c.add(o);//Collection集合只用单个存储元素,并且只能存储引用类型
27. Customer cus = new Customer("Jack", 20);
28. c.add(cus);
29.
30. //3.获取元素个数
31. System.out.println(c.size());//4
32. System.out.println(c.isEmpty());//false
33.
34. //4.将集合转换为Object类型的数组
35. Object[] objcets = c.toArray();
36.
37. for (int i = 0; i < objcets.length; i++) {
38. System.out.print(objcets[i] + "\t");
39. }
40. System.out.println();
41.
42. //5.清空
43. c.clear();
44. System.out.println(c.size());//0
45. System.out.println(c.isEmpty());//true
46. }
47. }
48.
49. class Customer {
50. private String name;
51. private int age;
52.
53. Customer(String name, int age) {
54. this.name = name;
55. this.age = age;
56. }
57.
58. public String getName() {
59. return name;
60. }
61.
62. public void setName(String name) {
63. this.name = name;
64. }
65.
66. public int getAge() {
67. return age;
68. }
69.
70. public void setAge(int age) {
71. this.age = age;
72. }
73.
74. @Override
75. public String toString() {
76. return "Customer{" +
77. "name='" + name + '\'' +
78. ", age=" + age +
79. '}';
80. }
81. }
82. /* -------------- 运行结果 --------------
83. 4
84. false
85. 1 100 java.lang.Object@506e1b77 Customer{name='Jack', age=20}
86. 0
87. true
88. -------------- 运行结果 -------------- */
Iterator iterator()
Iterator iterator(); 获取集合所依赖的迭代器对象
通过迭代器中方法完成集合的迭代(遍历)
1. package com.sust.cst.javase.selflearning.c20_Collection.t01_Collection;
2.
3. import java.util.Collection;
4. import java.util.Iterator;
5. import java.util.LinkedList;
6.
7. /*
8. Iterator iterator(); 获取集合所依赖的迭代器对象
9. 通过迭代器中方法完成集合的迭代(遍历)
10.
11. 注意:这种方式是所有集合通用的遍历方式
12. */
13. public class Test02 {
14. public static void main(String[] args) {
15. //1.创建集合对象
16. Collection c = new LinkedList();
17.
18. //添加元素
19. c.add(100);
20. c.add(3.14);
21. c.add(false);
22.
23. //迭代(遍历)
24. //1.获取迭代器对象
25. //不需要关心底层集合的具体类型,所有集合依赖的迭代器都实现了java.util.Iterator接口
26. Iterator iterator = c.iterator();//迭代器是面向接口编程
27. // it是一个引用,保存内存地址,指向堆中的“迭代器”对象
28.
29. //java.util.Linkedlist$ListItr 类是LinkedList集合所依赖的迭代器
30. //java.util.Arraylist$Itr 类是ArrayList集合所依赖的迭代器
31. System.out.println(iterator);
32.
33. //2.调用方法,完成遍历(迭代)
34. //while循环
35.
36. //boolean b = iterator.hasNext(); 判断是否有更多的元素,如果有返回true
37. while(iterator.hasNext()){
38. //Object o = it.next(); 将迭代器向下移动一位,并且取出指向的元素
39. Object element = iterator.next();
40. System.out.print(element + " ");
41. }
42. System.out.println();
43.
44. /*
45. 原则:调用it.next();之前,必须调用it.hasNext()
46. */
47.
48. //for循环
49. for(iterator = c.iterator();iterator.hasNext();){
50. Object o = iterator.next();
51. System.out.print(o + " ");
52. }
53. System.out.println();
54. }
55. }
56. /* -------------- 运行结果 --------------
57. java.util.LinkedList$ListItr@b4c966a
58. 100 3.14 false
59. 100 3.14 false
60. -------------- 运行结果 -------------- */
boolean contains(Object)
boolean contains(Object element); 判断集合中是否包含某个元素
1. package com.sust.cst.javase.selflearning.c20_Collection.t01_Collection;
2.
3. import java.util.ArrayList;
4. import java.util.Collection;
5.
6. /*
7. boolean contains(Object element); 判断集合中是否包含某个元素
8.
9. 存储在集合中的元素应该重写equals方法
10. */
11. public class Test03 {
12. public static void main(String[] args) {
13. //创建集合
14. Collection c = new ArrayList();
15.
16. //创建1个Integer类型的对象
17. Integer i1 = new Integer(10);
18.
19. //添加元素
20. c.add(2);
21. c.add(4);
22. c.add(6);
23. c.add(8);
24. c.add(i1);
25.
26. //判断集合中是否包含i1
27. System.out.println(c.contains(i1));//true
28.
29. //创建1个Integer类型的对象
30. Integer i2 = new Integer(10);
31.
32. //contains方法底层调用的是equals方法,如果equals返回true,就是包含
33. System.out.println(c.contains(i2));//true
34.
35. /*
36. public boolean contains(Object o) {
37. return indexOf(o) >= 0;
38. }
39. public int indexOf(Object o) {
40. return indexOfRange(o, 0, size);
41. }
42.
43. int indexOfRange(Object o, int start, int end) {
44. Object[] es = elementData;
45. if (o == null) {
46. for (int i = start; i < end; i++) {
47. if (es[i] == null) {
48. return i;
49. }
50. }
51. } else {
52. for (int i = start; i < end; i++) {
53. if (o.equals(es[i])) {
54. return i;
55. }
56. }
57. }
58. return -1;
59. }
60. */
61.
62. Manager m1 = new Manager(100,"Jack");
63. c.add(m1);
64. System.out.println(c.contains(m1));//true
65.
66. Manager m2 = new Manager(100,"Jack");
67. //重写equals方法之前
68. //System.out.println(c.contains(m2));//false
69.
70. //重写equals方法之后,比较内容
71. System.out.println(c.contains(m2));//true
72. }
73. }
74.
75. class Manager{
76. int no;
77. String name;
78.
79. public Manager(int no, String name) {
80. this.no = no;
81. this.name = name;
82. }
83.
84. @Override
85. public String toString() {
86. return "Manager{" +
87. "no=" + no +
88. ", name='" + name + '\'' +
89. '}';
90. }
91.
92. //重写Manager的equals方法
93. //需求规定:如果姓名和编号都相同,则表示一个Manager
94. public boolean equals(Object o){
95. boolean retBool = false;
96.
97. if(this == o)
98. retBool = true;
99. if(o instanceof Manager){
100. Manager m = (Manager)o;
101. if(m.no == this.no && m.name.equals(this.name))
102. retBool = true;
103. }
104.
105. return retBool;
106. }
107. }
108. /* ------ 运行结果 ------
109. true
110. true
111. true
112. true
113. ------ 运行结果 ------ */
boolean remove(Object o)
boolean remove(Object o); 删除集合中某个元素
remove和contains方法都需要集合中的元素重写equals方法,因为Object中的equals方法比较内存地址,在显示的业务逻辑当中不能比较内存地址,该比较内容。
1. package com.sust.cst.javase.selflearning.c20_Collection.t01_Collection;
2.
3. import java.util.ArrayList;
4. import java.util.Collection;
5.
6. /*
7. boolean remove(Object o); 删除集合中某个元素
8.
9. remove和contains方法都需要集合中的元素重写equals方法,
10. 因为Object中的equals方法比较内存地址,在显示的业务逻辑当中
11. 不能比较内存地址,该比较内容
12. */
13. public class Test04 {
14. public static void main(String[] args) {
15.
16. //创建集合对象
17. Collection c = new ArrayList();
18.
19. Integer i1 = new Integer(10);
20.
21. //添加元素
22. c.add(i1);
23.
24. //删除
25. Integer i2 = new Integer(10);
26. c.remove(i2);
27.
28. System.out.println(c.size());//0
29.
30. Manager m1 = new Manager(100,"Smith");
31. c.add(m1);
32.
33. Manager m2 = new Manager(100,"Smith");
34. c.remove(m2);
35.
36. System.out.println(c.size());//0
37. }
38. }
39. /* -------- 运行结果 --------
40. 0
41. 0
42. -------- 运行结果 -------- */
深入remove方法
迭代器的remove方法和集合自身带的remove方法的区别:
c集合自身删除一个元素之后,整体就改变了,需要重新获取迭代器才能接续往下执行。
1. package com.sust.cst.javase.selflearning.c20_Collection.t01_Collection;
2.
3. import java.util.ArrayList;
4. import java.util.Collection;
5. import java.util.Iterator;
6.
7. /*
8. 深入remove方法
9. 1.迭代器的remove方法
10. 2.集合自身带的remove方法
11. */
12. public class Test05 {
13. public static void main(String[] args) {
14.
15. Collection c = new ArrayList();
16.
17. c.add(1);
18. c.add(2);
19. c.add(3);
20.
21. //遍历
22. Iterator it = c.iterator();
23.
24. while(it.hasNext()){
25. //推荐使用迭代器自身带的remove方法删除元素
26. it.next();
27. //删除
28. it.remove();//通过迭代器删除
29.
30. /* //使用集合自身所带的remove方法
31. Object element = it.next();
32.
33. //删除
34. c.remove(element);*/
35.
36. /*
37. Exception in thread "main" java.util.ConcurrentModificationException
38. at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
39. at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
40. at com.sust.cst.javase.selflearning.c20_Collection.t01_Collection.Test05.main(Test05.java:30)
41. */
42. }
43.
44. System.out.println(c.size());//0
45. }
46. }
47. /* -------- 运行结果 --------
48. 0
49. -------- 运行结果 -------- */
List集合
List集合存储元素特点:
- 有序(List集合存储有下标):存进去是这样的顺序,取出来还是按照这个顺序取出
- 可重复
1. package com.sust.cst.javase.selflearning.c20_Collection.t02_List;
2.
3. import java.util.ArrayList;
4. import java.util.Iterator;
5. import java.util.List;
6.
7. /*
8. List集合存储元素的特点
9. */
10. public class Test01 {
11. public static void main(String[] args) {
12.
13. //创建一个List集合
14. List l = new ArrayList();
15.
16. l.add(1123);
17. l.add(2);
18. l.add(12);
19. l.add(1290);
20. l.add(1534);
21.
22. //遍历
23. Iterator it = l.iterator();
24.
25. while(it.hasNext()){
26. System.out.println(it.next());
27. }
28. }
29. }
30. /* -------- 运行结果 --------
31. 1123
32. 2
33. 12
34. 1290
35. 1534
36. -------- 运行结果 -------- */
深入List集合
ArrayList集合底层是数组,数组是有下表的,因此他有许多自己的特性。
ArrayList集合底层默认初始化容量是 10 ,扩大之后的容量是原容量的 1.5 倍。
Vetor集合底层默认初始化容量也是10,扩大之后的容量是原容量的2倍。
如何优化ArrayList和Vetor?
尽量减少扩容操作,因为扩容需要数组拷贝,很耗内存。
一般推荐在创建集合的时候指定初始化容量。
1. package com.sust.cst.javase.selflearning.c20_Collection.t02_List;
2.
3. import java.util.ArrayList;
4. import java.util.Iterator;
5. import java.util.LinkedList;
6. import java.util.List;
7.
8. /*
9. 深入List集合
10. */
11. public class Test02 {
12. public static void main(String[] args) {
13. //创建List集合
14. //List l = new ArrayList();
15. List l = new LinkedList();
16.
17. //添加元素
18. l.add(123);
19. l.add(234);
20. l.add(69);
21. //在下标为1的位置上添加555
22. l.add(1,555);
23.
24. //取得第一个元素
25. System.out.println(l.get(0));//123
26. System.out.println("-------------------");
27. //遍历(List集合特有的遍历方式)
28. for(int i = 0; i< l.size();i++){
29. Object element = l.get(i);
30. System.out.print(element + " ");
31. }
32. System.out.println();
33. System.out.println("-------------------");
34.
35. //迭代器
36. Iterator it = l.iterator();
37. while (it.hasNext()){
38. System.out.print(it.next() + " ");
39. }
40. }
41. }
42. /* ----------- 运行结果 -----------
43. 123
44. -------------------
45. 123 555 234 69
46. -------------------
47. 123 555 234 69
48. ----------- 运行结果 ----------- */
Set
HashSet
- 哈希表/散列表数据结构示意图
- HashSet底层实际上是一个HashMap.HashMap底层采用了哈希表数据结构
- 哈希表又叫做散列表,哈希表底层是一个数组,这个数组中每一个元素是一个单项链表,每个单向链表都有一个独一无二的哈希值代表数组的下标。在某个单向链表中的每一个节点上的哈希值是相等的。哈希值实际上是key调用hashCode方法,再通过”hash function”转换成的值。
- 如何向哈希表中添加元素:
- 调用被存储的key的hashcode方法,经过某个算法得出哈希值
- 如果在这个哈希表中不存在这个hash值,则直接加入元素,如果该hash值已经存在,则继续调用key之间的equals方法。
- 如果equals方法返回false,则将该元素添加
- 如果equals方法返回true,则放弃添加该元素
- HashSet其实是HashMap中的key部分,HashSet有什么特点,HashMap中的key应该具有相同的特点。
- HashMap和HashSet初始化容量都是 16,默认加载因子是 0.75
1. package com.sust.cst.javase.selflearning.c20_Collection.t03_Set.m01_HashSet;
2.
3. import java.util.HashSet;
4. import java.util.Iterator;
5. import java.util.Set;
6.
7. public class Test01 {
8. public static void main(String[] args) {
9. //创建set集合
10. Set s = new HashSet();
11. //无需不可重复
12. s.add(1);
13. s.add(1);
14.
15. s.add(100);
16. s.add(88);
17. s.add(89);
18. s.add(8394);
19. s.add(1293);
20. s.add(23);
21. s.add(45);
22.
23. //遍历
24. Iterator it = s.iterator();
25. while(it.hasNext()){
26. System.out.println(it.next());
27. }
28. }
29. }
30. /* -------- 运行结果 --------
31. 1
32. 100
33. 23
34. 88
35. 89
36. 8394
37. 1293
38. 45
39. -------- 运行结果 -------- */
关于往Set集合中存储的元素,该元素的hashCode和equals方法
HashMap中有一个put方法,put(key, value),key是无序不可重复的
结论:存储在HashSet集合或者HashMap集合key部分的元素,需要同时重写equals和hashCode方法
1. package com.sust.cst.javase.selflearning.c20_Collection.t03_Set.m01_HashSet;
2.
3. import java.util.HashSet;
4. import java.util.Iterator;
5. import java.util.Set;
6.
7. /*
8. 关于往Set集合中存储的元素,该元素的HashCode和equals方法
9. HashMap中有一个put方法,put(key, value) key是无序不可重复的
10.
11. 结论:存储在HashSet集合或者HashMap集合Key部分的元素,需要同时重写equals和hashCode方法
12. */
13. public class Test02 {
14. public static void main(String[] args) {
15. //创建集合
16. Set es = new HashSet();
17. Employee[] employees = new Employee[6];
18. String[] names = {"Jack", "Jack", "Scott", "Sun", "Jim", "Cook"};
19. String[] nos = {"1000", "1000", "1000", "2001", "3000", "3001"};
20.
21. System.out.println(employees.length);
22.
23. for (int i = 0; i < employees.length; i++) {
24. employees[i] = new Employee(nos[i], names[i]);
25. }
26.
27. for (int i = 0; i < employees.length; i++) {
28. System.out.println("employees[" + i + "].hashCode() = " +
29. employees[i].hashCode());
30. }
31.
32. //添加元素
33. for (int i = 0; i < employees.length; i++) {
34. es.add(employees[i]);
35. }
36.
37. //产看集合元素个数
38. System.out.println(es.size());
39.
40. Iterator it = es.iterator();
41. while (it.hasNext()) {
42. System.out.println(it.next());
43. }
44.
45. // while(es.iterator().hasNext()){
46. // System.out.println(es.iterator().next());
47. // }
48. }
49. }
50.
51. class Employee {
52. //编号
53. private String no;
54. private String name;
55.
56. public Employee(String no, String name) {
57. this.no = no;
58. this.name = name;
59. }
60.
61. public Employee() {
62. this(null, null);
63. }
64.
65. public String getNo() {
66. return no;
67. }
68.
69. public void setNo(String no) {
70. this.no = no;
71. }
72.
73. public String getName() {
74. return name;
75. }
76.
77. public void setName(String name) {
78. this.name = name;
79. }
80.
81. //重写equals方法
82. @Override
83. public boolean equals(Object o) {
84. if (this == o) return true;
85. if (!(o instanceof Employee)) return false;
86. Employee employee = (Employee) o;
87. return no.equals(employee.no) &&
88. name.equals(employee.name);
89. }
90.
91.
92. //重写hashCode方法
93. @Override
94. public int hashCode() {
95. //以员工编号分组
96. return this.no.hashCode();
97. }
98.
99. @Override
100. public String toString() {
101. return "Employee{" +
102. "no='" + no + '\'' +
103. ", name='" + name + '\'' +
104. '}';
105. }
106. }
SortedSet和TreeSet
- java.util.SortedSet;继承java.util.Set类,java.util.TreeSet;类为SortedSet类的子类。
- SortedSet类中的元素无序不可重复,但是存进去的元素可以按照元素大小顺序自动排列。
- Integer类,String类,Date类都已经实现了Comparable接口
1. package com.sust.cst.javase.selflearning.c20_Collection.t03_Set.m02_SortedSetAndTreeSet;
2.
3. import java.text.ParseException;
4. import java.text.SimpleDateFormat;
5. import java.util.Date;
6. import java.util.Iterator;
7. import java.lang.Object;
8. import java.util.SortedSet;
9. import java.util.TreeSet;
10.
11. /*
12. java.util.Set;
13. java.util.SortedSet; 无序不可重复,但是存进去的元素可以按照元素大小顺序自动排列
14. java.util.TreeSet;
15. */
16. public class Test01 {
17. public static void main(String[] args) throws ParseException {
18.
19. //创建集合
20. SortedSet sortedSet = new TreeSet();
21.
22. //添加元素
23. for (int i = 0; i < 6; i++) {
24. sortedSet.add((int) (Math.random() * 1000) % 100);
25. }
26.
27. //遍历
28. Iterator it = sortedSet.iterator();
29. while (it.hasNext()) {
30. System.out.print(it.next() + " ");
31. }
32. System.out.println();
33.
34. //String
35. SortedSet strSet = new TreeSet();
36.
37. String[] strings = {"Jack", "Sun", "Kook", "Lucy", "King"};
38.
39. for (int i = 0; i < strings.length; i++) {
40. strSet.add(strings[i]);
41. }
42.
43. //遍历
44. it = strSet.iterator();
45. while (it.hasNext()) {
46. System.out.print(it.next() + " ");
47. }
48. System.out.println();
49. System.out.println();
50.
51. //日期
52. String[] stime = { "2008-08-08",
53. "2009-08-08",
54. "2010-06-08",
55. "2010-04-23",
56. "2012-08-08" };
57.
58. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
59. Date[] t = new Date[5];
60. for (int i = 0; i < t.length; i++) {
61. t[i] = sdf.parse(stime[i]);
62. }
63.
64. SortedSet times = new TreeSet();
65. for (int i = 0; i < t.length; i++) {
66. times.add(t[i]);
67. }
68.
69. it = times.iterator();
70. while (it.hasNext()) {
71. Object element = it.next();
72. if (element instanceof Date) {
73. Date d = (Date) element;
74. System.out.println(sdf.format(d));
75. }
76. }
77. }
78. }
79. /* ----------- 运行结果 -----------
80. 0 1 3 19 26 61
81. Jack King Kook Lucy Sun
82.
83. 2008-08-08
84. 2009-08-08
85. 2010-04-23
86. 2010-06-08
87. 2012-08-08
88. ----------- 运行结果 ----------- */
SortedSet集合存储元素为什么可以自动排序?
因为被存储的元素实现了Comparable接口,SUN编写TreeSet集合在添加元素的时候,会调用CompareTo方法完成比较。
1. package com.sust.cst.javase.selflearning.c20_Collection.t03_Set.m02_SortedSetAndTreeSet;
2.
3. import java.util.Iterator;
4. import java.util.SortedSet;
5. import java.util.TreeSet;
6.
7. /*
8. SortedSet集合存储元素为什么可以自动排序?
9. */
10. public class Test02 {
11. public static void main(String[] args) {
12. SortedSet users = new TreeSet();
13.
14. User[] u = new User[5];
15. for (int i = 0; i < u.length; i++) {
16. u[i] = new User((int) (Math.random() * 100) % 20);
17. }
18.
19. //添加元素
20. for (int i = 0; i < u.length; i++) {
21. users.add(u[i]);
22. }
23. /* User类未实现Comparable接口时发生的错误
24. Exception in thread "main" java.lang.ClassCastException: class com.sust.cst.javase.selflearning.c20_Collection.t03_Set.m02_SortedSetAndTreeSet.User cannot be cast to class java.lang.Comparable (com.sust.cst.javase.selflearning.c20_Collection.t03_Set.m02_SortedSetAndTreeSet.User is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
25. at java.base/java.util.TreeMap.compare(TreeMap.java:1291)
26. at java.base/java.util.TreeMap.put(TreeMap.java:536)
27. at java.base/java.util.TreeSet.add(TreeSet.java:255)
28. at com.sust.cst.javase.selflearning.c20_Collection.t03_Set.m02_SortedSetAndTreeSet.Test02.main(Test02.java:21)
29. */
30.
31. Iterator it = users.iterator();
32. while (it.hasNext()) {
33. System.out.println(it.next());
34. }
35. }
36. }
37.
38. class User implements Comparable {
39. int age;
40. String name;
41.
42. public User(int age) {
43. this.age = age;
44. }
45.
46. @Override
47. public String toString() {
48. return "User{" +
49. "age=" + age +
50. '}';
51. }
52.
53. //该方法程序员负责实现,SUN提供的程序已经调用了该方法
54. //需求:按照User的age排序
55. @Override
56. public int compareTo(Object o) {
57. //编写比较规则
58. int age1 = this.age;
59. int age2 = ((User) o).age;
60.
61. //return this.name.compareTo(((User) o).name);
62. return age1 - age2;
63. }
64. }
65. /* ---------- 运行结果 ----------
66. User{age=3}
67. User{age=5}
68. User{age=10}
69. User{age=16}
70. User{age=19}
71. ---------- 运行结果 ---------- */
让SortedSet集合做到排序还有另一种方式:java.util.Comparator;
单独写一个比较器
第一种方式,设计的程序和程序之间关联程度比较强,耦合度较高
第二种方式,单独写一个比较器,对原先写出的类的影响比较小,所以推荐使用"单独写一个比较器"的方式.
Map
关于Map集合中常用的方法。
1. package com.sust.cst.javase.selflearning.c20_Collection.t04_Map;
2.
3. import java.util.*;
4.
5. /*
6. 关于Map中常用的方法
7.
8. void clear(); 清空Map
9. boolean containsKey(Object Key); 判断Map中是否包含这样的Key
10. boolean containsValue(Object Value); 判断Map中是否包含这样的value
11. Set<Map, Entry<K,V>> entrySet() 返回此映射关系的Set视图
12. Object get(Object key); 通过Key获取value
13. boolean isEmpty(); 判断该集合是否为空
14. Set keySet(); 获取Map中所有的key
15. Object put(Object key, Object value); 向集合中添加键值对
16. Object remove(Object key); 通过key将键值对删除
17. int size(); 获取Map中键值对的个数
18. Set keySet(); 获取Map中所有的key
19. Collection values(); 获取Map集合中所有的value
20.
21. 注意:存储在Map集合key部分的元素需要同时重写hashCode+equals方法
22. */
23. public class Test01 {
24. public static void main(String[] args) {
25. //1.创建map集合
26. Map persons = new HashMap();//HashMap的默认初始化容量是16,默认加载因子是0.75
27.
28. //2.存储键值对
29. String[] id = {"10000", "10011", "10002", "10003", "10004", "10000"};
30.
31. String[] name = {"Jack", "Sun", "King", "Cock", "Jack", "Lucy"};
32.
33. for (int i = 0; i < id.length; i++) {
34. persons.put(id[i], name[i]);
35. }
36.
37. //注意:Map中如果key重复了,value采用的是“赋值”
38. Iterator it = persons.keySet().iterator();
39. while(it.hasNext()){
40. System.out.print(persons.get(it.next()) + " ");
41. }
42. System.out.println();
43.
44. //判断键值对的个数
45. //Map中的key是无序不可重复的,和HashSet相同
46. System.out.println(persons.size());//5
47.
48. //判断集合中是否包含这样的key
49. System.out.println(persons.containsKey("10000"));//true
50.
51. //判断集合中是否包含这样的value
52. System.out.println(persons.containsValue("Lucy"));//true
53.
54. //通过key获取value
55. String kStr = "10011";
56. Object value = persons.get(kStr);
57. System.out.println(value);//Sun
58.
59. //通过key删除键值对
60. persons.remove("10002");
61. System.out.println(persons.size());//4
62.
63. //获取所有的value
64. Collection values = persons.values();
65. it = values.iterator();
66. while (it.hasNext()){
67. System.out.print(it.next() + " ");//Lucy Sun Jack Cock
68. }
69. System.out.println();
70.
71. //获取所有的key
72. //以下程序演示如何遍历Map集合
73. Set keys = persons.keySet();
74. it = keys.iterator();
75. while(it.hasNext()){
76. Object k = it.next();
77. Object v = persons.get(k);
78. System.out.println(k + "-->" + v);
79. }
80. System.out.println();
81.
82. //entrySet
83. //将Map转换成Set集合 这种方式不常用,因为常常把key拿出来使用
84. Set personEntrySet = persons.entrySet();
85. it = personEntrySet.iterator();
86. while(it.hasNext()){
87. System.out.println(it.next());
88. }
89. }
90. }
91. /* ---------- 运行结果 ----------
92. Lucy Sun King Jack Cock
93. 5
94. true
95. true
96. Sun
97. 4
98. Lucy Sun Jack Cock
99. 10000-->Lucy
100. 10011-->Sun
101. 10004-->Jack
102. 10003-->Cock
103.
104. 10000=Lucy
105. 10011=Sun
106. 10004=Jack
107. 10003=Cock
108. ---------- 运行结果 ---------- */
Propertier
1. package com.sust.cst.javase.selflearning.c20_Collection.t04_Map;
2.
3. import java.util.Properties;
4.
5. /*
6. Hashtable默认初始化容量是 11 ,默认加载因子是 0.75
7.
8. java.util.Properties; 也是由key和value组成,但是key和value都是字符串类型
9. */
10. public class Test02 {
11. public static void main(String[] args) {
12. //创建属性类对象
13. Properties p = new Properties();
14.
15. //setProperty 存
16. p.setProperty("driver","oracle.jdbc.driver.OracleDriver");
17. p.setProperty("username","scott");
18.
19. //注意:key不能重复,如果重复则value会被覆盖
20. p.setProperty("username","aaaa");
21. p.setProperty("password","tiger");
22. p.setProperty("url","jdbc:oracle:thin:@192.168.1.100.1521:bjpowernode");
23.
24. //getProperty 取,通过key获取value
25. String v1 = p.getProperty("driver");
26. String v2 = p.getProperty("username");
27. String v3 = p.getProperty("password");
28. String v4 = p.getProperty("url");
29.
30. System.out.println(v1);
31. System.out.println(v2);
32. System.out.println(v3);
33. System.out.println(v4);
34. }
35. }
36. /* --------------------- 运行结果 ---------------------
37. oracle.jdbc.driver.OracleDriver
38. aaaa
39. tiger
40. jdbc:oracle:thin:@192.168.1.100.1521:bjpowernode
41. --------------------- 运行结果 --------------------- */
SortedMap & TreeMap
SortedMap中的key特点:无序不可重复,但是存储的元素可以按照大小自动排列。
如果想自动排序,key部分的元素需要:
1.实现Comparable接口
2.单独写一个比较器
1. package com.sust.cst.javase.selflearning.c20_Collection.t04_Map;
2.
3. import java.util.*;
4.
5. /*
6. SortedMap中的key特点:无序不可重复,但是存储的元素可以按照大小自动排列。
7. 如果想自动排序,key部分的元素需要:
8. 1.实现Comparable接口
9. 2.单独写一个比较器
10. */
11. public class Test03 {
12. public static void main(String[] args) {
13.
14. //Map,key存储商品,value存储个数
15. //SortedMap products = new TreeMap();
16.
17. //匿名内部类单独写一个比较器
18. SortedMap products = new TreeMap(new Comparator() {
19. @Override
20. public int compare(Object o1, Object o2) {
21. double price1 = ((Product)o1).getPrice();
22. double price2 = ((Product)o2).getPrice();
23. int retvalue = 0;
24.
25. if(price1 > price2){
26. retvalue = 1;
27. }else if(price1 < price2){
28. retvalue = -1;
29. }
30.
31. return retvalue;
32. }
33. });
34.
35. //准备对象
36. Product[] p = new Product[4];
37. String[] names = {"西瓜", "苹果", "桃子", "香蕉"};
38. double[] prices = {1.0, 4.0, 5.0, 3.0};
39.
40. for (int i = 0; i < p.length; i++) {
41. String proName = names[i];
42. double proPrice = prices[i];
43.
44. p[i] = new Product(proName, proPrice);
45. }
46.
47. //添加
48. double[] weight = {8.0, 3.0, 4.0, 10.0};
49.
50. for(int i = 0; i < p.length;i++){
51. products.put(p[i],weight[i]);
52. }
53.
54. //遍历
55. Set keys = products.keySet();
56. Iterator it = keys.iterator();
57. while(it.hasNext()){
58. Object k = it.next();
59. Object v = products.get(k);
60. System.out.println(k + "-->" + v + "kg");
61. }
62. }
63. }
64.
65. //实现comparable接口
66. class Product {//implements Comparable {
67. private String name;
68. private double price;
69.
70. public Product(String name, double price) {
71. this.name = name;
72. this.price = price;
73. }
74.
75. public String getName() {
76. return name;
77. }
78.
79. public void setName(String name) {
80. this.name = name;
81. }
82.
83. public double getPrice() {
84. return price;
85. }
86.
87. public void setPrice(double price) {
88. this.price = price;
89. }
90.
91. @Override
92. public String toString() {
93. return "Product{" +
94. "name='" + name + '\'' +
95. ", price=" + price +
96. "元" +
97. '}';
98. }
99.
100. /* //需求:按照商品价格排序
101. @Override
102. public int compareTo(Object o) {
103. double price1 = this.price;
104. double price2 = ((Product) o).price;
105. int rtnValue = 0;
106.
107. if (price1 < price2) {
108. rtnValue = -1;
109. } else if (price1 > price2) {
110. rtnValue = 1;
111. }
112.
113. return rtnValue;
114. }*/
115. }
116. /* ---------------- 运行结果 ----------------
117. Product{name='西瓜', price=1.0元}-->8.0kg
118. Product{name='香蕉', price=3.0元}-->10.0kg
119. Product{name='苹果', price=4.0元}-->3.0kg
120. Product{name='桃子', price=5.0元}-->4.0kg
121. ---------------- 运行结果 ---------------- */
Collections集合工具类
1. package com.sust.cst.javase.selflearning.c20_Collection.t05_Collections;
2.
3. import java.util.*;
4.
5. /*
6. 关于集合工具类 java.util.Collections;
7.
8. java.util.Collections; 是一个类
9. java.util.Collection; 是集合接口
10. */
11. public class Test01 {
12. public static void main(String[] args) {
13.
14. //使用Collections工具完成集合的排序
15. List l = new ArrayList();
16.
17. //添加元素
18. l.add(10);
19. l.add(5);
20. l.add(7);
21. l.add(123);
22. l.add(3425);
23.
24. //遍历
25. System.out.println("---------- List集合排序前 ----------");
26. for (int i = 0; i < l.size(); i++) {
27. System.out.print(l.get(i) + " ");
28. }
29. System.out.println();
30.
31. Iterator it = l.iterator();
32. while (it.hasNext()) {
33. System.out.print(it.next() + " ");
34. }
35. System.out.println();
36.
37. for (it = l.iterator(); it.hasNext(); ) {
38. System.out.print(it.next() + " ");
39. }
40. System.out.println();
41. System.out.println("---------- List集合排序后 ----------");
42.
43. //排序
44. Collections.sort(l);
45.
46. //遍历
47. it = l.iterator();
48. while (it.hasNext()) {
49. System.out.print(it.next() + " ");
50. }
51. System.out.println();
52.
53. System.out.println("---------- Set集合排序前 ----------");
54.
55. //给定Set集合
56. Set s = new HashSet();
57. s.add(1);
58. s.add(3);
59. s.add(1234);
60. s.add(325);
61. s.add(1123);
62. it = s.iterator();
63. while (it.hasNext()) {
64. System.out.print(it.next() + " ");
65. }
66. System.out.println();
67.
68. //对Set集合排序
69. //Collections.sort(s);
70. /*
71. Error:(61, 20) java: 对于sort(java.util.Set), 找不到合适的方法
72. 方法 java.util.Collections.<T>sort(java.util.List<T>)不适用
73. (无法推断类型变量 T
74. (参数不匹配; java.util.Set无法转换为java.util.List<T>))
75. 方法 java.util.Collections.<T>sort(java.util.List<T>,java.util.Comparator<? super T>)不适用
76. (无法推断类型变量 T
77. (实际参数列表和形式参数列表长度不同))
78. */
79.
80. //将Set集合转换成List集合
81. List listS = new ArrayList(s);
82. Collections.sort(listS);
83.
84. //遍历
85. System.out.println("---------- Set集合转换为ArrayList集合排序后 ----------");
86. for (int i = 0; i < listS.size(); i++) {
87. System.out.print(listS.get(i) + " ");
88. }
89.
90. //创建list集合,List集合中存储Person类型,是否可以排序?
91. //Collections工具类可以对List集合中的元素排序,但是集合中的元素必须是“可比较的”,实现Comparable接口
92. /*List persons = new ArrayList();
93. persons.add(new Person());
94. persons.add(new Person());
95. persons.add(new Person());
96. persons.add(new Person());
97.
98. Collections.sort(persons);*/
99. /*
100. class
101. com.sust.cst.javase.selflearning.c20_Collection.t05_Collections.Person
102. cannot be cast to
103. class
104. java.lang.Comparable
105. */
106.
107. //将ArrayList集合转换成线程安全的
108. List myList = new ArrayList();
109. Collections.synchronizedList(myList);
110. }
111. }
112.
113. class Person {
114.
115. }
116. /* -------------------- 运行结果 --------------------
117. ---------- List集合排序前 ----------
118. 10 5 7 123 3425
119. 10 5 7 123 3425
120. 10 5 7 123 3425
121. ---------- List集合排序后 ----------
122. 5 7 10 123 3425
123. ---------- Set集合排序前 ----------
124. 1 1234 3 1123 325
125. ---------- Set集合转换为ArrayList集合排序后 ----------
126. 1 3 325 1123 1234
127. -------------------- 运行结果 -------------------- */
泛型JDK5.0新特性 编译期感念
为什么引入泛型?
- 可以统一集合中的数据类型
- 可以减少强制类型转换
泛型的优点和缺点
优点:统一类型,减少强制转换。
缺点:只能存储一种类型。
1. package com.sust.cst.javase.selflearning.c20_Collection.t06_Generics;
2.
3. import java.util.HashSet;
4. import java.util.Iterator;
5. import java.util.Set;
6.
7. /*
8. 以下程序不适用泛型的缺点?
9. 如果集合不适用泛型,则集合中的元素类型就不统一。
10. 在遍历集合的时候只能拿出来Object类型,需要做大量的强制类型转换,很麻烦。
11. */
12. public class Test01 {
13. public static void main(String[] args) {
14. //创建一个集合,存储ABC
15. Set s = new HashSet();
16.
17. A a = new A();
18. B b = new B();
19. C c = new C();
20.
21. s.add(a);
22. s.add(b);
23. s.add(c);
24.
25. //
26. Iterator it = s.iterator();
27. while(it.hasNext()){
28. Object o = it.next();
29. //只能做大量的强制类型转换
30. if(o instanceof A){
31. A sA = (A)o;
32. sA.m1();
33. }else if(o instanceof B){
34. B sB = (B)o;
35. sB.m2();
36. }else if(o instanceof C){
37. C sC = (C)o;
38. sC.m3();
39. }
40. }
41. }
42. }
43.
44. class A{
45. public void m1(){
46. System.out.println("A ---> m1");
47. }
48. }
49. class B{
50. public void m2(){
51. System.out.println("B ---> m2");
52. }
53. }
54. class C{
55. public void m3(){
56. System.out.println("C ---> m3");
57. }
58. }
59. /* ------- 运行结果 -------
60. B ---> m2
61. A ---> m1
62. C ---> m3
63. ------- 运行结果 ------- */
泛型语法如何实现
泛型是一个编译阶段的语法,在编译阶段统一集合中的类型。
1. package com.sust.cst.javase.selflearning.c20_Collection.t06_Generics;
2.
3. import com.sun.source.util.Trees;
4.
5. import java.util.*;
6.
7. /*
8. 泛型如何实现?
9. */
10. public class Test02 {
11. public static void main(String[] args) {
12. //创建一个List集合,只能存储字符串类型
13. System.out.println("\n-------- List使用泛型 --------");
14. List<String> strs = new ArrayList<String>();
15.
16. //添加元素
17. //strs.add(1);
18. //Error:(15, 18) java: 不兼容的类型: int无法转换为java.lang.String
19.
20. strs.add("Jack");
21. strs.add("Sun");
22. strs.add("Lucy");
23. strs.add("Sim");
24. strs.add("Lyon");
25.
26. Iterator<String> it = strs.iterator();
27. while (it.hasNext()) {
28. String s = it.next();
29. System.out.print(s + " ");
30. }
31. System.out.println();
32.
33. /*
34. Map使用泛型
35. */
36. System.out.println("\n-------- Map使用泛型 --------");
37. Map<String, Integer> maps = new HashMap<String, Integer>();
38. //存
39. maps.put("西瓜", 10);
40. maps.put("苹果", 30);
41. maps.put("菠萝", 8);
42. maps.put("榴莲", 23);
43.
44. //遍历
45. Set<String> keys = maps.keySet();
46. Iterator<String> it2 = keys.iterator();
47. while (it2.hasNext()) {
48. String k = it2.next();
49. Integer v = maps.get(k);
50. System.out.println(k + "----->" + v);
51. }
52.
53. /*
54. SortedSet集合使用泛型
55. */
56. System.out.println("\n-------- SortedSet集合使用泛型 --------");
57. SortedSet<Manager> ss = new TreeSet<Manager>();
58.
59. //添加元素
60. Manager[] managers = new Manager[5];
61.
62. double[] sals = {100.0, 2200.0, 3500.0, 2453.5, 1334.0};
63. for(int i = 0; i < managers.length;i++){
64. managers[i] = new Manager(sals[i]);
65. }
66.
67. for(int i = 0; i < managers.length;i++){
68. ss.add(managers[i]);
69. }
70.
71. //遍历
72. Iterator<Manager> it3 = ss.iterator();
73. while(it3.hasNext()){
74. Manager m = it3.next();
75. m.work();
76. System.out.println(m);
77. }
78.
79. }
80. }
81.
82. class Manager implements Comparable<Manager>{
83. double sal;
84.
85. public Manager(double sal) {
86. this.sal = sal;
87. }
88.
89. public void work(){
90. System.out.println("在工作,一个月" + sal + "元");
91. }
92.
93. @Override
94. public String toString() {
95. return "Manager{" +
96. "sal=" + sal +
97. '}';
98. }
99.
100. @Override
101. public int compareTo(Manager o) {
102. double sal1 = this.sal;
103. double sal2 = o.sal; //此处不需要强制类型转换了
104. int retval = 0;
105.
106. if(sal1 > sal2){
107. retval = -1;
108. }else if(sal1 < sal2){
109. retval = 1;
110. }
111.
112. return retval;
113. }
114. }
115. /* ---------------- 运行结果 ----------------
116. -------- List使用泛型 --------
117. Jack Sun Lucy Sim Lyon
118.
119. -------- Map使用泛型 --------
120. 苹果----->30
121. 榴莲----->23
122. 西瓜----->10
123. 菠萝----->8
124.
125. -------- SortedSet集合使用泛型 --------
126. 在工作,一个月3500.0元
127. Manager{sal=3500.0}
128. 在工作,一个月2453.5元
129. Manager{sal=2453.5}
130. 在工作,一个月2200.0元
131. Manager{sal=2200.0}
132. 在工作,一个月1334.0元
133. Manager{sal=1334.0}
134. 在工作,一个月100.0元
135. Manager{sal=100.0}
136. ---------------- 运行结果 ---------------- */
自定义泛型
1. package com.sust.cst.javase.selflearning.c20_Collection.t06_Generics;
2. /*
3. 自定义泛型
4. */
5. public class Test03 {
6. public static void main(String[] args) {
7. MyClass<String> mc = new MyClass<String>();
8.
9. //泛型就是编译期检查类型
10. //Error
11. //mc.m1(100);
12. //Error:(8, 15) java: 不兼容的类型: int无法转换为java.lang.String
13.
14. mc.m1("Jack");
15. }
16. }
17.
18. //自定义泛型
19. class MyClass<T>{//T --> Type E --> Element
20. public void m1(T t){
21. System.out.println(t);
22. }
23. }
24. /* --- 运行结果 ---
25. Jack
26. --- 运行结果 --- */
增强for循环 foreach
语法:
for(类型 变量:数组名/集合名){}
集合要想使用增强for循环这种语法,集合需要使用泛型
如果不使用泛型,需要用Object类型来定义集合中的元素
1. package com.sust.cst.javase.selflearning.c20_Collection.t07_foreach;
2.
3. import java.util.ArrayList;
4. import java.util.HashSet;
5. import java.util.List;
6. import java.util.Set;
7.
8. /*
9. 关于增强for循环
10. */
11. public class Test01 {
12. public static void main(String[] args) {
13. int[] a = {1,2,3,4};
14.
15. //遍历
16. System.out.println("\n* 数组使用普通方式遍历 -------------");
17. for( int i = 0; i < a.length;i++){
18. System.out.print(a[i] + " ");
19. }
20. System.out.println();
21.
22. //foreach
23. System.out.println("\n* 数组使用foreach方式遍历 ----------");
24. for(int x:a){//int x代表的是集合或者数组中的某个元素
25. System.out.print(x + " ");
26. }
27. System.out.println();
28.
29. //集合
30. Set<String> strs = new HashSet<String>();
31. strs.add("Jack");
32. strs.add("Lucy");
33. strs.add("Lyon");
34. strs.add("Max");
35.
36. //遍历
37. System.out.println("\n* 集合使用foreach方式遍历 ----------");
38. for(String name:strs){
39. System.out.print(name + " ");
40. }
41. System.out.println();
42.
43. //集合不使用泛型
44. System.out.println("\n* 集合使用泛型遍历 -----------------");
45. List l = new ArrayList();
46. l.add(1);
47. l.add(2);
48. l.add(3);
49. l.add(4);
50.
51. //如果集合不使用泛型,该集合在使用增强for循环的时候应该用Object类型定义
52. for(Object element:l){
53. System.out.print(element + " ");
54. }
55. System.out.println();
56. }
57. }
58. /* ---------------- 运行结果 ----------------
59. * 数组使用普通方式遍历 -------------
60. 1 2 3 4
61.
62. * 数组使用foreach方式遍历 ----------
63. 1 2 3 4
64.
65. * 集合使用foreach方式遍历 ----------
66. Max Lyon Lucy Jack
67.
68. * 集合使用泛型遍历 -----------------
69. 1 2 3 4
70. ---------------- 运行结果 ---------------- */
增强for循环的缺点:没有下标
1. package com.sust.cst.javase.selflearning.c20_Collection.t07_foreach;
2. /*
3. 关于增强for的缺点:没有下标
4. */
5. public class Test02 {
6. public static void main(String[] args) {
7. String[] ins = {"运动","音乐","旅游","美食"};
8.
9. System.out.println("\n* 使用for循环-------------");
10. StringBuffer sb1 =new StringBuffer();
11. for(int i = 0; i < ins.length;i++){
12. if(i == ins.length-1)
13. sb1.append(ins[i]);
14. else{
15. sb1.append(ins[i]);
16. sb1.append(",");
17. }
18. }
19. System.out.println(sb1);
20.
21. //以上的循环就不适合使用增强for
22. System.out.println("\n* 使用增强for循环---------");
23. StringBuffer sb2 =new StringBuffer();
24. for(String s:ins){
25. sb2.append(s);
26. sb2.append(",");
27. }
28. //截取掉最后的","
29. System.out.println(sb2.substring(0,sb2.length()-1));
30. }
31. }
32. /* ------- 运行结果 -------
33. * 使用for循环-------------
34. 运动,音乐,旅游,美食
35.
36. * 使用增强for循环---------
37. 运动,音乐,旅游,美食
38. ------- 运行结果 ------- */