Java零基础极速入门
文章目录
本套教程基于 Java17 和 IDEA2022,专为 Java 初学者量身定制。通过本套教程的学习,你将掌握 Java 语言的整体结构和学习体系、Java 基础语法及简单应用,为后续 Web 开发、Spring 框架的学习打下坚实的基础。
Java发展
总结:适合小白,弱化底层,强化语法,简单应用
1 Java快速入门
1.1计算机语言
与计算机沟通的说明书,人和计算机之间通信的语言,编写计算机程序的数字、字符和语法规则
1.2 Java语言
机器语言、编程语言、指令代码
编程:用倾向于自然语言的方式编写指令代码的过程
编译:将自然语言指令代码转化为机器语言(二进制)的过程
1.3 JVM
系统差异化:为了用不同类型的芯片实现相同的功能,就需要用不同的指令代码操作不同的计算机硬件设备
解决方法:Java 可以通过软件模拟虚拟机器(JVM),用一套代码操作相同的虚拟机器上,从而屏蔽不同计算机设备的差异,简化指令代码的编写
字节码:JVM 接收的指定代码
JDK:Java Development Kit,Java 开发工具包,封装经常使用的指令代码和编译器
JRE:Java Runtime Environment,Java 运行环境,可以直接使用编译好的字节码
1.4 环境配置
略
2 基础语法
2.1 变量
cpu分配内存的过程
1.占用存储空间(重复太多,内存占用太大)
2.建立了关系(减少了内存的占用但牵一发而动全身)
3.折中(减少冗余,降低影响)
数据存储:只存储数据
向量存储:存储数据类型、大小、位置(指向)
变量:可以改变的向量存储
创建变量:在内存空间中创建向量存储
变量即是可以改变的向量存储
声明:数据类型 + 变量名称
赋值:变量名称 = 数据
使用:直接访问变量名称即可
初始化:使用变量之前,必须给变量赋值
public static void main(String[] args) {
// TODO 变量
// 所谓得变量,其实就是可以改变得向量存储
// TODO 1. 声明变量
// 数据类型 变量名称
String name;
// TODO 2. 变量赋值
name = "lisi";
// TODO 3. 变量使用
System.out.println(name);
System.out.println(name);
System.out.println(name);
System.out.println(name);
System.out.println(name);
// 实际开发时,可以将第一步和第二步合并在一起
String username = "wangwu";
System.out.println(username);
}
2.2 标识符
标识数据的符号,主要用于起名
命名规则:
1.英文拉丁字母(汉语拼音)
2.符号 @ # %
,但
∗
∗
标识符只能用
∗
∗
<
u
>
<
f
o
n
t
c
o
l
o
r
=
′
r
e
d
′
>
下划线
<
/
f
o
n
t
>
<
/
u
>
∗
∗
和
∗
∗
∗
∗
<
f
o
n
t
c
o
l
o
r
=
′
r
e
d
′
>
,但 **标识符只能用**<u><font color='red'>下划线</font></u>**和** **<font color='red'>
,但∗∗标识符只能用∗∗<u><fontcolor=′red′>下划线</font></u>∗∗和∗∗∗∗<fontcolor=′red′>** 符号,其他符号不能使用,包括空格也属于特殊符号,不能作为标识符使用
3.数字(0-9),可以使用,但不能用作命名开头
4.区分大小写,在大括号{}范围内命名不允许重复
5.关键字(保留字):Java 中预先定义好了一些标识符名称,不允许重复定义
6.驼峰命名法(规范命名):多个单词拼接,第一个单词首字母小写,其他单词首字母大写
7.标识符长度无限制
8.中文亦可命名,但容易出现乱码
public static void main(String[] args) {
// TODO 标识符
// 所谓得标识符,其实就是用于标记数据得符号,变量名就是标识符
// 主要用于起名
String name = "zhangsan";
// TODO 标识符得命名规则
// 1. 拉丁字母
// 有意义得英文单词
String username = "lisi";
String xingming = "wangwu";
// wx, qq
// 2. 符号
// @ # %
// Java语法中只能使用美元$符号和下划线作为标识符,其他符号称之为特殊符号,不能作为标识符
// 空格也属于特殊符号,所以也不能作为标识符使用
String user_name = "zhangsan";
String user$name = "zhangsan";
//String user@name = "zhangsan";
//String user#name = "zhangsan";
//String user name = "zhangsan";
// 3. 数字
// 阿拉伯数字 0 ~ 9也可以作为标识符使用
String name1 = "zhangsan";
String name_1 = "zhangsan";
// 如果标识符以数字开头,那么会被识别为数字,那么就不能作为标识符使用了。
//String 1name = "zhangsan";
// 4. 标识符得重复问题(区分大小写)
// 在同一个大括号内,标识符不能重复
// Java中标识符是区分大小写得。
String Name = "lisi";
// 5. 预先定义好得标识符名称(关键字,保留字)
// 所有得关键字和保留字都是采用小写,所以如果采用大写是没有问题。
String Static = "zhangsan";
// 6. 多个单词拼接在一起(驼峰标识)
String userName = "zhangsan";
// 7 . 标识符得长度没有限制
}
2.3数据类型
数据得存储单位
1.比特(bit位) : 数据运算得最小存储单位
2.字节(byte) : 数据最小存储单位
3.bit和byte可以互相转换得
1 byte = 8 bit位
4.其他单位
KB, MB, GB, TB…PB, EB…
1024 Byte => 1KB
1024 KB => 1MB
1024 MB => 1GB
1024 GB => 1TB
Java 的数据类型可以确定数据范围
基础数据类型:
1.整数类型:
a.byte 8位
b.short 16位
c.int 32位
d.long 64位
2.浮点类型:
a.float:单精度浮点数
b.double:双精度浮点数
c.默认情况下,小数点数据会被识别为精度更高的双精度 double 类型
d.如果想要设置单精度,数据需要使用 F / f 结尾
3.字符类型:
a.char
b.用符号(单引号)表示文字内容
4.布尔类型:
a.boolean
b.true or false
public static void main(String[] args) {
// TODO 基本数据类型
// TODO 1. 整数类型
// byte : 8位
byte b = 10;
// short : 16位
short s = 10;
// int : 32位
int i = 10;
// long : 64位
long lon = 10;
// TODO 2. 浮点类型:含有小数点得数据类型
// 根据计算精度分为
// 默认情况下,小数点得数据会被识别位精度较高得双精度double类型
// float : 单精度浮点类型,数据需要使用F(f)结尾
float f = 1.0F;
// double : 双精度浮点类型
double d = 2.0;
// TODO 3. 字符类型
// 所谓得字符类型,其实就是使用符号标识文字内容
char c = '@';
// TODO 4. 布尔类型
// true, false,标识判断条件是否成立,如果成立,取值位true,如果不成立,那么取值位false
boolean bln = true;
}
数据类型转换:
-
注意数据类型
不同数据类型不能赋值转换
-
注意数值范围(从小到大)
byte – short – int – long – float – double
-
范围大的数据无法直接转换为范围小的数据,但可以使用小括号间接强制转换
public static void main(String[] args) {
// TODO 数据类型的转换
String name = "zhangsan";
int age = 30;
name = "lisi";
//name = age;
// byte -> short -> int -> long -> float -> double
byte b = 10;
short s = b;
int i = s;
long lon = i;
float f = lon;
double d = f;
// Java中范围小的数据可以直接转换位范围大的数据,但是范围大的数据无法直接转换位范围小的数据
// 如果想要将范围大的数据转换位范围小的数据,那么需要使用小括号进行强制转换。
int i1 = (int)d;
}
byte和char的关系
public static void main(String[] args) {
// TODO byte和char的关系
// char(16 bit) -> byte(8 bit)
// asc码
// gb2112 gbk
// shift_jis
// Java : Unicode
// asc码字符 : 一个字节就是一个字符
// 其他编码字符 : 3个字节是一个字符
String s = "中国a";
String 姓名 = "中国a";
// 获取字节的数量
System.out.println(s.getBytes().length);
// 获取字符的数量
System.out.println(s.toCharArray().length);
}
引用数据类型:
1.可以被引用的数据类型(存储时箭头的指向,变量指向引用数据类型)
2.变量如果是基本数据类型,在存储时不会有相应箭头(只有向量存储)
3.包括 string、类、数组、接口、枚举、null 等
2.4 运算符
运算符:
1.参与数据运算的符号
2.和字符不同,无法自行定义
3.表达式:运算符 + 数据,符合Java语法规则的指令代码
4.运算符分类:
算术运算符
1.**二元运算符:**两个元素参与运算
- 3*2 //6
- 1/2 //0
- 1.0/2 //0.5
- 5%2 //1
- 表达式的结果类型是元素种类类型最大的那一种,最小使用的类型为 int(可以强转)
2.**一元运算符:**一个元素参与运算
- ++,– 自增/自减运算符
- ++i,i++ 先+1/后+1
3.赋值运算符:
- =
- 将右边的表达式结果赋值给左边的变量
- 元素运算后重新赋值给自己,复合赋值,如:+= i
- 如果使用 复合赋值运算符,数据的类型不会发生变化,如:byte b1 += 20
4.关系运算符:
- 比较两个数据之间的关系
- ==, !=, >= 等
- 结果为布尔类型
5.逻辑运算符:
- 描述多个条件表达式之间关系的运算符
- 变量 = 条件表达式1 逻辑运算符 条件表达式2
- 结果为布尔类型
- & :与,两个条件表达式都要计算出结果,全true得true,其他false
- |: 或,两个条件表达式都要计算出结果,有true得true,没true得false、
- && :短路与,根据第一个表达式的结果决定是否执行第二个条件表达式,如果第一个就能判断出结果(false),则不会执行第二个
- ||: 短路或,如果第一个就能判断出结果(true),则不会执行第二个
- ! :非,相反运算
6.三元运算符:
- 三个元素参与运算
- 变量 = 条件表达式 ? 任意表达式1 : 任意表达式2
- 判断:如果条件表达式结果为true,执行任意表达式1,false则执行任意表达式2
public static void main(String[] args) {
// TODO 运算符
// 所谓得运算符就是参与数据运算得符号,Java定义得,无法执行定义
// TODO 表达式
// 所谓得表达式就是采用运算符和数据连接在一起形成符合Java语法规则得指令代码,称之为表达式
// TODO 算术运算符
// 1. 二元运算符 : 两个元素参与运算得运算符, 1 + 2
// TODO 算术表达式 = 元素1 二元运算符 元素2
// 这个表达式是有结果得,就需要有类型,这里得类型是元素种类型最大的那一种, 最小使用的类型为int类型
// System.out.println(1 + 2); // 3
// System.out.println(2 - 2); // 0
// System.out.println(3 * 2); // 6
// System.out.println(4 / 2); // 2
// System.out.println(1 / 2); // 0.5 (int, int) => int
// System.out.println(1.0 / 2); // 0.5 (double, int) => double
// System.out.println(5 % 2); // 1 (取余,模运算)
// byte b1 = 10;
// byte b2 = 20;
// byte b3 = (byte)(b1 + b2); // (int, int) => int
//System.out.println( 1 + 2 * 3 ); // 7
// System.out.println( (1 + 2) * 3 ); // 9
// 2. 一元运算符 : 一个元素参与运算得运算符
// ++, --
// ++ 运算符的本质其实就是加1操作的简化版本,自增运算符
// ++ 运算符的本质其实就是减1操作的简化版本,自减运算符
// int i = 0;
// //int j = i; // j = 0
// //i = i + 1; // i = 1
// int j = i++;
// System.out.println("i = " + i);
// System.out.println("j = " + j);
// int i = 0;
// i = i + 1; // i = 1
// int j = i; // j = 1
// int j = ++i;
// System.out.println("i = " + i);
// System.out.println("j = " + j);
// int i = 1;
int j = i; // j = 1
i = i - 1; // i = 0
// int j = i--;
// System.out.println("i = " + i);
// System.out.println("j = " + j);
int i = 1;
// i = i - 1; // i = 0
// int j = i; // j = 0
int j = --i;
System.out.println("i = " + i);
System.out.println("j = " + j);
}
public static void main(String[] args) {
// TODO 运算符 - 赋值运算符
// 等号其实就是赋值运算符:将等号右边表达式的结果赋值给等号左边的变量
// 赋值运算符需要考虑类型的关系
// String name = "zhangsan";
// byte b = 10;
// short s = b;
// TODO 复合赋值运算符: +=
// 如果元素进行运算后重新赋值给自己,那么可以将运算和赋值的符号进行简化
// 如果使用了复合赋值运算符,那么数据的类型不会发生变化。
// int i = 1;
// //i = i + 1;
// //i = i * 1;
// i *= 2;
// System.out.println(i);
byte b1 = 10;
//b1 = b1 + 20; // int => byte
b1 += 20;
System.out.println(b1);
}
public static void main(String[] args) {
// TODO 运算符 - 关系运算符
// 所谓的关系运算符其实就是用于比较两个数据之间关系的运算符
// 关系运算符基本语法结构:
// TODO 关系表达式: 元素1(数据1,表达式1) 关系运算符[==, !=, >, >=, <, <=] 元素2(数据2,表达式2)
// 关系表达式的结果为布尔类型:如果表达式结果为预想相同,那么结果为true,如果表达式结果和预想不同,那么结果为false
int i = 10;
int j = 20;
System.out.println( i == j ); // false 双等号表示 两个数据是否相等
System.out.println( i != j ); // true 感叹号等号表示 两个数据是否不相等
System.out.println( i > j ); // false
System.out.println( i >= j ); // false, 大于等于表示 等于也可以,等于也可以
System.out.println( i < j ); // true
System.out.println( i <= j ); // true 小于等于表示 小于也可以,等于也可以
}
public static void main(String[] args) {
// TODO 运算符 - 逻辑运算符
// 所谓的逻辑运算符其实就是用于描述多个条件表达式之间的关系的运算符
// TODO 基本的语法结构:
// 变量 = (条件表达式1) 逻辑运算符 (条件表达式2)
// 结果的变量的类型依然为布尔类型
// 因为条件表达式的结果类型为布尔类型,所以逻辑运算符表达式的结果类型也是布尔类型,但是分几种情况:
// true true => ?
// false true => ?
// false false => ?
// true false => ?
// TODo 逻辑运算符:&, 称之为与运算
// 与运算,要求两个条件表达式都必须计算出结果,只有当两个结果都是true时,最终结果为true,其他情况全是false
// int i = 10;
// boolean result = (i < 5) & ( i < 20);
// System.out.println(result);
// TODo 逻辑运算符:|, 称之为或运算
// 或运算,要求两个条件表达式都必须计算出结果,只要任何一个结果为true,那么最后结果就是true
// 两个表达式的结果都是false,那么最终的结果才是false
// int i = 10;
// boolean result = (i < 5) | ( i > 20);
// System.out.println(result);
// TODo 逻辑运算符:&&, 称之为短路与运算
// 短路与运算, 会根据第一个条件表达式的结果来判断,是否执行第二个条件表达式。
// 如果第一个表达式的结果为false,那么就无需执行第二个表达式
// int i = 10;
// int j = 20;
// boolean result = (i > 10) && ( ++j > 30 );
// System.out.println(result);
// System.out.println(j);
// TODo 逻辑运算符:||, 称之为短路或运算
// 短路或运算, 会根据第一个条件表达式的结果来判断,是否执行第二个条件表达式。
// int i = 10;
// int j = 20;
// boolean result = (i == 10) || ( ++j > 30 );
// System.out.println(result);
// System.out.println(j);
// TODo 逻辑运算符:!, 称之为非(相反)运算
// true => false
// false => true
int i = 10;
boolean result = i == 10;
boolean result1 = i > 10;
System.out.println(!result);
System.out.println(!result1);
}
public static void main(String[] args) {
// TODO 运算符 - 三元运算符
// 所谓的三元运算符其实就是三个元素参与运算的运算符
// 基本语法结构:
// 变量 = (条件表达式)?(任意表达式1):(任意表达式2)
// 运算规则:判断条件表达式的结果,如果为true,那么执行任意表达式1的值,如果为false,那么执行任意表达式2的值
int i = 15;
int j = 20;
int k = ( i == 10 ) ? 1 + 1 : 2 + 2;
System.out.println(k);
}
2.5 流程控制
流程控制:
1.计算机在执行代码时对指令代码执行顺序的控制
2.Java 流程控制主要分三种:
- 顺序执行
- 分支执行
- 重复执行
3.顺序执行
- 按代码和语法出现的先后顺序执行
4.分支执行
- 根据判断条件执行分支逻辑
- 可选分支、必选分支(多选一)、多分支、特殊分支(switch)
5.重复执行
- 根据条件循环执行
- while、do … while、for
- break 和 continue
分支执行:
- 可选分支(单分支,if true or false)
- 必选分支(双分支,if / else)
- 多分支(多重判断,if / else if / {else})
- 特殊分支(等值判断,switch case
- switch:
- 会对数据进行判断,如果等于某一个分支数据的值,会执行该分支的逻辑代码,并顺序执行后面的分支
- 如果一个分支都无法匹配,那么一个分支都不会执行,此时如果还想执行分支,可以增加 default 关键字(必选)
- 如果执行某个分支后,不想再执行其他分支,可以使用 break 关键字跳出当前分支
小练习:根据年龄判断成长阶段
public class Java04_FlowControl_Test {
public static void main(String[] args) {
// TODO 流程控制 - 分支执行 - 小练习
int age = 45;
// 儿童(0~6),少年(7~17),青年(18~40),中年(41~ 65),老年(66)
// if ... else if ... else if... else :多分支判断
// switch...case ...case ... default : 等值分支判断
// if ( age < 7 ) {
// System.out.println("儿童");
// } else if ( age >= 7 && age < 18 ) {
// System.out.println("少年");
// } else if ( age >= 18 && age < 41 ) {
// System.out.println("青年");
// } else if ( age >= 41 && age < 66 ) {
// System.out.println("中年");
// } else {
// System.out.println("老年");
// }
if ( age < 7 ) {
System.out.println("儿童");
} else if ( age < 18 ) {
System.out.println("少年");
} else if ( age < 41 ) {
System.out.println("青年");
} else if ( age < 66 ) {
System.out.println("中年");
} else {
System.out.println("老年");
}
}
}
重复执行:
- **while:**有条件循环
-
while (条件表达式) {}
-
先判断条件,{} 执行完毕后,重新判断条件
-
小心死循环
2.do {} while:
-
先执行 do{},再判断条件
-
至少执行一次
3.for ( a; b; c) :
-
初始化表达式(用于条件表达式中的变量初始化)
-
条件表达式(决定是否执行循环)
-
更新表达式(控制循环次数)
-
break 跳出当前层循环,不再执行后续操作
-
continue 跳过当前层的这次循环,继续执行下次循环
6.小练习:九层妖塔
- 结合使用 print 和 println
- 嵌套循环找规律
public class Java06_FlowControl_Test {
public static void main(String[] args) {
// TODO 流程控制 - 小练习
// 九层妖塔
/*
*
***
*****
*******
4 => 0 -> 3
4 => 1 -> 2
4 => 2 -> 1
*/
/*
// 打印第一层的数据
for (int i = 0; i < 1; i++) {
System.out.print("*");
}
System.out.println("");
// 打印第二层的数据
// println方法打印字符串之后,会自动添加换行符
// print方法打印字符串后,不换行
for (int i = 0; i < 3; i++) {
System.out.print("*");
}
System.out.println("");
// 打印第三层的数据
for (int i = 0; i < 5; i++) {
System.out.print("*");
}
System.out.println("");
// 打印第四层的数据
for (int i = 0; i < 7; i++) {
System.out.print("*");
}
System.out.println("");
*/
// 0 -> 1
// 1 -> 3
// 2 -> 5
// 3 -> 7
// 4 -> 9
int level = 3;
for ( int j = 0; j < level; j++ ) {
for ( int i = 0; i < (level-1) - j; i++ ) {
System.out.print(" ");
}
for (int i = 0; i < j * 2 + 1; i++) {
System.out.print("*");
}
System.out.println("");
}
}
}
2.6 面向对象
1.面向过程:把大象装进冰箱里分三步
2.思考方式:如果需要解决很多类似问题,每次梳理步骤过程就会比较麻烦,但如果直接去分析问题涉及的具体事物(Object,对象),会更符合日常生活的思考方式,这就叫“面向对象编程”
3.面向对象:是一种编程思想,一种分析事物和解决问题的方式,我们通过编程语言的语法来体现这种思想
基本语法:
1.类和对象:
- 类表示归纳和整理
- 对象表示具体事物
2.类的语法基本语法结构:
class 类名 {
特征(属性),
功能(方法)
}
创建对象的语法:
new 类名();
3.步骤:
TODO 1. 先声明类
TODO 2. 创建对象
TODO 3. 声明属性,所谓的属性其实就是类中的变量
变量类型 变量名称 = 变量值
属性类型 属性名称 = 属性值
TODO 4. 声明方法
void 方法名(参数){ 功能代码 }
TODO 5. 执行方法
对象.属性
对象.方法名()
案例:
public class Java01_Object {
public static void main(String[] args) {
// TODO 面向对象
//所谓的面向对象,其实就是分析问题时,以问题所涉及到的事或物为中心的分析方式
// 类和对象
// 类表示归纳和整理
// 对象就表示具体的事物
// TODO class(类)
/*
类的语法基本语法结构:
class 类名 {
特征(属性),
功能(方法)
}
创建对象的语法:
new 类名();
*/
// 问题:做一道菜,红烧排骨
// 类:菜, 对象:红烧排骨
// TODO 1. 先声明类
// TODO 2. 创建对象
// TODO 3. 声明属性,所谓的属性其实就是类中的变量
// 变量类型 变量名称 = 变量值
// 属性类型 属性名称 = 属性值
// TODO 4. 声明方法
// void 方法名(参数){ 功能代码 }
// TODO 5. 执行方法
// 对象.属性
// 对象.方法名()
// 引用数据类型
Cooking c = new Cooking();
c.name = "红烧排骨";
c.food = "排骨";
c.execute();
Cooking c1 = new Cooking();
c1.name = "红烧鱼";
c1.food = "鲫鱼";
c1.execute();
}
}
class Cooking {
// 特征(属性)
// 名字
String name;
// 菜的类型
String type = "红烧";
// 食材
String food;
// 佐料
String relish = "大料";
// TODO 执行
void execute() {
System.out.println("准备食材:" + food);
System.out.println("准备佐料:" + relish);
System.out.println("开始烹饪");
System.out.println(name + "烹饪完成");
}
}
注意:
- 在对同一个对象的不同属性进行操作的时候,需要用变量来引用这个对象
- Cooking c = new Cooking()
- 创建对象,用对象类型的变量来引用它,当处理变量时,处理的其实是引用的对象
- 基本数据类型不是对象,因此不是引用数据类型
- 用“+”拼接字符串
- 如果需要新菜,用new再次创建即可
类:
- 结构体,里面包含了属性(特征)和方法(行为) 会有很多的对象。
- class : 关键字(全是小写)
- 类名:类的名称,标识符。遵循规则。一般情况下,类名的首写字母是大写。
对象:
-
类的实例化(具象化)
-
new 类名(),下括号需要增加。
-
new也是关键字,表示创建一个具体的对象,而且,使用一次,创建一次,每次都是全新的。
一般new出来的对象会赋值给变量,方便重复使用
-
变量的类型就是对象的类型。
-
对象是将内存地址赋值给了变量,所以变量其实引用了内存中的对象,所以称之为引用变量,
而变量的类型称之为引用数据类型。
-
特殊的对象:空对象(null),没有引用的对象,称之为空对象, 关键字对象。
-
所有引用类型变量的默认取值就是null
**内存分为三个部分:**栈、堆、元空间
栈 存储方法、变量 User user
堆 存储对象 new User()
元空间 存储类的信息
属性:
-
所谓的属性,其实就是类的对象的相同特征。
-
语法和变量的声明很像。
-
属性类型 属性名称 = 属性值
-
如果在声明属性的同时进行了初始化赋值,那么所有对象的属性就完全相同
-
所以如果希望每个对象的属性不一致,那么可以不用在声明属性的时候进行初始化。
-
那么属性会在构造对象的时候默认初始化,而默认初始化的值取决鱼属性的类型.
-
byte ,short, int ,long => 0
-
float, double => 0.0
-
boolean flg = false
-
char = 空字符
-
引用数据类型 => null
-
变量 是方法的一部分 作用域非常小,只在当前的大括号内有效
-
属性 是对象的一部分 不仅仅在当前类中有效,而且可以随着对象在其他地方使用
-
变量使用前必须初始化,否则会出现错误,属性可以不用初始化,因为JVM会帮助我们自动完成初始化。
方法:
- 类的行为称之为方法。
- 基本的语法为:void 方法名(){ 方法的逻辑代码 }
- 既然方法是对象的行为,那么行为就会有结果,而结果可能会对其他对象有影响
- 扩展语法: 返回值类型[void] 方法名(){ 方法的逻辑代码 }
- 方法就是行为,所以会有结果,如果想要结果给其他人使用,那么需要在方法中返回这个结果。 void关键字表示无需返回,也就是方法的结果没有人使用。
- 如果想要结果给其他人使用,那么需要在方法中返回结果,并将void改成返回值的类型。
- 方法的结果需要采用return关键字进行返回。
名词:类、属性
动词:方法(注意调用顺序,比如先注册后登录)
方法的调用方式:对象.方法名()
案例:
public class Java06_Object_Method {
public static void main(String[] args) {
// TODO 面向对象 - 方法
// 类的行为称之为方法。
// TODO 基本的语法为:void 方法名(){ 方法的逻辑代码 }
// 既然方法是对象的行为,那么行为就会有结果,而结果可能会对其他对象有影响
// TODO 扩展语法: 返回值类型[void] 方法名(){ 方法的逻辑代码 }
// 方法就是行为,所以会有结果,如果想要结果给其他人使用,那么需要在方法中返回这个结果。
// void关键字表示无需返回,也就是方法的结果没有人使用。
// 如果想要结果给其他人使用,那么需要在方法中返回结果,并将void改成返回值的类型。
// 方法的结果需要采用return关键字进行返回。
User06 user = new User06();
boolean registerResult = user.register();
if ( registerResult ) {
System.out.println("注册成功,请登录");
boolean loginResult = user.login();
if (loginResult) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
} else {
System.out.println("注册不成功,请重新注册");
}
}
}
class User06 {
boolean register() {
System.out.println("注册软件系统");
// 成功 true
return false;
// 失败 false
}
boolean login() {
System.out.println("登录软件系统");
return true;
}
}
方法参数:
-
使用外部数据控制方法内部实现的操作(参数语法)
-
内部:方法名(参数类型 参数名称)
-
外部:传递参数
-
当方法传递多个参数时,参数个数、类型、顺序都要匹配
-
当参数个数不确定,但类型相同时,可以采用 可变参数 语法声明
-
格式:参数类型… 参数名称(String… name)
-
如果方法头还包含其他类型参数,可变参数应声明在最后
public class Java07_Object_Method_Param {
public static void main(String[] args) {
// TODO 面向对象 - 方法 - 参数
// 从外部获取数据控制方法的内容逻辑实现的语法操作,我们称之为参数。也叫方法参数。
// 方法的参数语法类似于变量:类型 名称,但是需要在方法后面的小括号中使用
// 参数可以有多个,如果有多个,那么使用逗号隔开。
// 如果方法声明了参数,那么调用时必须传递参数,否则发生错误。
// TODO 扩展语法: 返回值类型[void] 方法名(参数类型 参数名)
// 如果参数有多个的话,那么在传值的时候需要注意:
// 1. 个数不能缺失
// 2. 类型必须匹配
// 3. 顺序必须匹配
// 将方法后面的小括号中的所有参数称之为参数列表
// 如果参数的类型(含义)相同,但是个数不确定的场合,JVM提供了可变参数 : 参数的长度可变
// 参数类型...参数名
// 传值的个数也可以是变化的。
// User07 user = new User07();
// user.sayHello("zhangsan", 30);
// user.sayHello(40, "lisi");
User07 user = new User07();
user.printUser(30);
user.printUser(40, "zhangsan");
user.printUser(50, "zhangsan", "lisi", "wangwu");
// 如果参数列表中含有不同含义的多个参数,那么可变参数必须放置在最后,否则出现错误
}
}
class User07 {
// void sayHello( String name, int age ) {
// System.out.println("Hello "+name);
// }
void printUser( int age, String... name ) {
System.out.println(name);
}
}
参数传值:
-
方法执行在栈内存中完成,在栈帧中存放参数、变量、执行逻辑
-
保持CPU箭头不变,调用新方法压栈、执行完方法弹栈
- 引用对象及属性存于堆中,调用新方法压栈时,传递箭头(同一个引用地址),但如果进行 字符串拼接 等操作,会创建一个新的字符串(指向新的引用地址)(传递 对象 修改属性不会),如果执行方法内的 s = s + 10,则 新s 和 原s 指向的不是同一个引用地址,因此,执行完毕后,会弹出方法内的 新s 和引用地址,打印出的还是 原s
-
Java 中方法参数的传递为 值传递
-
基本数据类型传数值,引用数据类型传引用地址
public class Java07_Object_Method_Param_1 {
public static void main(String[] args) {
// TODO 面向对象 - 方法 - 参数
// Java种方法参数的传递为值传递
// 基本数据类型:数值
// 引用数据类型:引用地址
// String s = "abc";
// test(s);
// System.out.println(s);// abc10
User user = new User();
user.name = "zhangsan";
test(user);
System.out.println(user.name);
}
// public static void test(int i) {
// i = i + 10;
// }
// public static void test(String s) {
// s = s + 10;
// }
public static void test(User user) {
user.name = "lisi";
}
}
class User {
String name;
}
静态:
-
针对于具体对象的属性称为对象属性,成员属性,实例属性
-
针对于具体对象的方法称为对象方法,成员方法,实例方法
-
static:和对象无关,只和类相关(可以通过 类名. 直接访问)
-
先有类,再有对象
-
有成员方法的时候,静态方法(类)一定存在,因此 可在成员方法内部调用静态方法/属性,但静态方法不能访问成员方法/属性
public class Java08_Object_Static {
public static void main(String[] args) {
// TODO 面向对象
// 针对于具体对象的属性称之为对象属性,成员属性,实例属性
// 针对于具体对象的方法称之为对象方法,成员方法,实例方法
// 把和对象无关,只和类相关的称之为静态,
// 和类相关的属性称之为静态属性
// 和类相关的方法称之为静态方法
// 静态语法就是在属性和方法前增加static关键字
//Chinese c = new Chinese();
// Chinese c = null;
// c.name = "zhangsan";
//
// System.out.println("Hello " + c.name + ", " + c.nationality);
Bird.fly();
System.out.println(Bird.type);
}
}
class Bird {
static String type = "鸟";
static void fly() {
System.out.println("飞...");
}
}
class Chinese {
String name;
// 国籍
String nationality = "中国";
}
public class Java08_Object_Static_1 {
public static void main(String[] args) {
// TODO 面向对象 - 静态
// TODO 先有类,再有对象。
// 成员方法可以访问静态属性和静态方法
// 静态方法不可以访问成员属性和成员方法
Test t = new Test();
// t.sex = "女";
// t.test();
// t.test1();
// Test.test1();
}
}
class Test {
String name;
static String sex;
void test() {
//test1();
//System.out.println(sex);
System.out.println("test...");
}
static void test1() {
// test();
//System.out.println(name);
//System.out.println("test1...");
}
}
class Bird1 {
static String type = "鸟";
static void fly() {
System.out.println("飞...");
}
}
静态代码块:
static { xxx }
类的信息加载完成后,会自动调用静态代码块,可以完成静态属性的初始化(按照声明静态代码块顺序依次执行)
对象准备创建时(对象创建前),也会自动调用代码块 {xxx},但不是静态的
public class Java08_Object_Static_2 {
public static void main(String[] args) {
// TODO 面向对象 - 静态
// 类的信息加载完成后,会自动调用静态代码块,可以完成静态属性的初始化功能
// 对象准备创建时,也会自动调用代码块,但不是静态的
//User08.test();
new User08();
}
}
class User08 {
static {
// 静态代码块
System.out.println("静态代码块执行1");
}
static {
// 静态代码块
System.out.println("静态代码块执行2");
}
static void test() {
System.out.println("test...");
}
{
System.out.println("代码块执行1");
}
static {
// 静态代码块
System.out.println("静态代码块执行3");
}
{
System.out.println("代码块执行2");
}
}
包:
- 包主要用于分类管理
- package + 包路径(用 . 隔开)
- 一个类可以没有包,但不能使用多次
- 为了区分类名,一般都是小写
如:java(包).lang(包).Object(类)
- Java 中存在不同包的相同名称的类,可以写类的全名加以区分(包名 + 类名)
- JVM 会在使用时自动添加 java.lang 包
- 可以使用 import 在使用类前导入包(位于 package 后,class 前),可以多次使用
- 如果 import 了不同包中相同名称的类,如 Date,使用时最好还是增加包名
import java.util.*;
import java.sql.Date;
public class Java10_Object_Import {
public static void main(String[] args) {
// TODO 面向对象 - import
// import 主要用于在使用类前准备好了。
// import语句只能使用在package后,class前。
// import关键字可以多次使用,导入多个类
// 如果同一个包中需要导入大量的类,那么可以使用通配符星号来简化操作。
// 如果import了不同保重相同名称的类,那么还是需要在使用时增加包名。
// chapter04.Java10_Object_Import
String name = "zhangsan";
String name1 = "zhangsan";
java.util.Date d = new java.util.Date();
new ArrayList();
new Java10_Object_Import();
new Java10_Object_Import();
new User10();
}
}
class User10 {
}
构造方法:
- 用于构建对象,在 new 对象的时候调用执行
- 如果一个类中没有任何构造方法,JVM 会自动添加一个 公共的、无参的 构造方法,方便对象调用
- 类名 () { xxx }
- 构造方法也是方法,但是没有 void 关键字
- 方法和类名完全相同
- 构造方法也可以传递参数,一般用于对象属性的赋值
- 代码块 比构造方法先执行
public class Java11_Object_Instance {
public static void main(String[] args) {
// TODO 面向对象 - 构建对象
// 构造方法:专门用于构建对象
// 如果一个类中没有任何的构造方法,那么JVM会自动添加一个公共的,无参的构造方法,方便对象的调用
// TODO : 基本语法: 类名(){}
// 1. 构造方法也是方法,但是没有void关键字。
// 2. 方法名和类名完全 相同
// 3. 如果类中没有构造方法,那么JVM会提供默认的构造方法
// 4. 如果类中有构造方法,那么JVM不会提供默认的构造方法
// 5. 构造方法也是方法,所以也可以传递参数,但是一般传递参数的目的是用于对象属性的赋值
//System.out.println("before...");
User11 user = new User11("zhangsan");
//System.out.println("after...");
user.test();
System.out.println(user.username);
// 代码块,是在构造对象之前执行的
}
}
class User11 {
String username;
{
System.out.println("代码块1");
}
User11(String name) {
username = name;
System.out.println("user...");
}
{
System.out.println("代码块2");
}
void test() {
System.out.println("test...");
}
{
System.out.println("代码块3");
}
}
继承:
- 面向对象编程 3 个重要特征:继承、封装、多态
- 类存在父子关系,子类可以直接获取父类的成员属性和成员方法,提高开发效率,有利于代码维护升级
- 类的继承只能是单继承,一个类只能有一个父类,但一个父类可以有多个子类
- 子类 extends 父类
- 如果父类和子类含有相同的属性,那么可以采用特殊的关键字进行区分:super、this,都表示对象
- 构造方法:
- 父类对象是在子类对象创建前创建完成,创建子类对象前,会调用父类的构造方法完成父类的创建
- 默认情况下,子类对象构建时,会默认调用父类的构造方法完成父类对象的创建。使用的是super的方式,只不过JVM自动完成(无参构造方法)
- 如果父类提供构造方法,那么JVM不会提供默认的构造方法,那么子类应该显示调用super方法构建父类对象。
- new 只会构建一个对象,在内存中只会开辟一块空间存储创建的对象
public class Java12_Object_Extends {
public static void main(String[] args) {
// TODO 面向对象 - Extends - 继承
// 面向对象变成中有3个非常重要的特征:继承,封装,多态
// 类存在父子关系:子类可以直接获取到父类的成员属性和成员方法。
// 类的继承只能是单继承,一个类只能有一个父类,不能存在多个父类
// 一个父类可以有多个子类
// 继承采用extends语法: 子类 extends 父类
Child c = new Child();
System.out.println(c.name);
c.test();
}
}
class Parent {
String name = "zhangsan";
void test() {
System.out.println("test");
}
}
class Child extends Parent {
}
public class Java12_Object_Extends_1 {
public static void main(String[] args) {
// TODO 面向对象 - Extends - 继承
// 如果父类和子类含有相同的属性,那么可以采用特殊的关键字进行区分
// super & this.
Child1 c = new Child1();
//System.out.println(c.name);
c.test();
}
}
class Parent1 {
String name = "zhangsan";
}
class Child1 extends Parent1 {
String name = "lisi";
void test() {
System.out.println(super.name);
System.out.println(this.name);
System.out.println(name);
}
}
public class Java12_Object_Extends_2 {
public static void main(String[] args) {
// TODO 面向对象 - Extends - 继承
// 构造方法
// 父类对象是在子类对象创建前创建完成,创建子类对象前,会调用父类的构造方法完成父类的创建
// 默认情况下,子类对象构建时,会默认调用父类的构造方法完成父类对象的创建。使用的是super的方式,只不过JVM自动完成
// 如果父类提供构造方法,那么JVM不会提供默认的构造方法,那么子类应该显示调用super方法构建父类对象。
Child2 c1 = new Child2();
Child2 c2 = new Child2();
Child2 c3 = new Child2();
}
}
class Parent2 {
String username;
Parent2 (String name) {
username = name;
System.out.println("parent...");
}
}
class Child2 extends Parent2 {
Child2() {
super("zhangsan");
System.out.println("child...");
}
}
多态:
-
所谓的多态,其实就是一个对象在不同场景下表现出来的不同状态和形态
-
多态语法其实就是对对象的使用场景进行了约束
-
一个对象可以使用的功能取决于引用变量的类型
public class Java13_Object {
public static void main(String[] args) {
// TODO 面向对象 - 多态
// 所谓的多态,其实就是一个对象在不同场景下表现出来的不同状态和形态
// 多态语法其实就是对对象的使用场景进行了约束
// 一个对象可以使用的功能取决于引用变量的类型
Person p = new Person();
p.testPerson();
Person p1 = new Boy();
p1.testPerson();
//p1.testBoy();
Person p2 = new Girl();
p2.testPerson();
//p2.testGirl();
Boy boy = new Boy();
boy.testBoy();
Girl girl = new Girl();
girl.testGirl();
}
}
class Person {
void testPerson() {
System.out.println("test person...");
}
}
class Boy extends Person {
void testBoy() {
System.out.println("test boy...");
}
}
class Girl extends Person {
void testGirl() {
System.out.println("test girl...");
}
}
方法重载:
-
一个类中不能重复声明相同的方法/属性
-
这里相同的方法是指 方法名、参数列表相同,和返回值类型无关
-
**重载:**如果方法名相同,但参数列表(个数,顺序,类型)不相同,会认为是不同的方法,只不过名称一样
-
构造方法也存在方法重载,如:new User(xxx)
-
如果在一个构造方法中,想要调用其他的构造方法,那么需要使用特殊的关键字:this
-
基本数据类型在匹配方法时,可以在数值不变的情况下扩大数据精度
-
byte类型无法和char类型做转换,char没有负数,但byte有负数
public class Java14_Object {
public static void main(String[] args) {
// TODO 面向对象
// 一个类中,不能重复声明的相同的方法,也不能声明相同的属性
// 这里相同的方法指的是方法名,参数列表相同,和返回值类型无关
// 如果方法名相同,但是参数列表(个数,顺序,类型)不相同,会认为是不同的方法,只不过名称一样
// 这个操作在Java称之方法的重载
// 构造方法也存在方法的重载
User14 user = new User14("zhangsan");
user.login(1111);
user.login("123123");
user.login("zhangsan", "123123");
}
}
class User14 {
User14() {
System.out.println("user...");
}
User14(String name) {
System.out.println("user..." + name);
}
void login( String account, String password ) {
System.out.println("账号,密码登录");
}
void login(int tel) {
System.out.println("手机验证码登录");
}
void login(String wx) {
System.out.println("微信,支付宝登录");
}
}
public class Java14_Object_1 {
public static void main(String[] args) {
// TODO 面向对象
// 如果在一个构造方法中。想要调用其他的构造方法,那么需要使用特殊的关键字:this
User141 user1 = new User141();
//User141 user2 = new User141("zhangsan");
//User141 user3 = new User141("zhangsan", "男");
}
}
class User141 {
User141() {
this("zhangsan");
}
User141( String name ) {
this(name, "男");
}
User141( String name, String sex ) {
System.out.println(name + "," + sex);
}
}
public class Java14_Object_2 {
public static void main(String[] args) {
// TODO 面向对象
byte b = 10;
// test(b); bbb
// int => iii
// byte => 8
// short => 16
// char => 16
// int => 32
// 基本数据类型在匹配方法时,可以在数值不变的情况下,扩大数据的精度
// byte类型无法和char类型做转换,char没有负数,但是byte存在负数
// test(b);
}
// static void test( byte b ) {
// System.out.println("bbb");
// }
// static void test( short s ) {
// System.out.println("sss");
// }
static void test( char c ) {
System.out.println("ccc");
}
// static void test( int i ) {
// System.out.println("iii");
// }
}
方法重写:
-
父类对象的方法主要体现通用性,无法在特殊场合下使用,如果子类对象需要在特殊场合下使用,就需要重写方法的逻辑
-
重写并不意味着父类的方法被覆盖,只是当前场合不适用,使用super还是可以访问
-
**重写要求:**子类方法和父类方法方法名相同、返回值类型相同、参数列表相同
-
构造方法不能重写
-
一个对象方法的具体使用(直接、间接)是需要看具体对象的
-
一个对象属性的具体使用不需要看具体对象,属性在哪里声明在哪里使用
public class Java15_Object {
public static void main(String[] args) {
// TODO 面向对象 - 重写
// 方法的重写:父类对象的方法其实主要体现通用性,无法在特殊的场合下使用
// 如果子类对象需要在特殊的场合下使用,那么就需要重写方法的逻辑,这个操作在Java中称之为方法的重写
// 这里的重写,并不意味着父类的方法被覆盖掉,只是在当前场合不使用。如果使用super关键字还是可以访问
// 方法的重写要求,子类的方法和父类的方法,方法名相同,返回值类型相同,参数列表要相同
Child15 child = new Child15();
child.test();
}
}
class Parent15 {
String name = "zhangsan";
void test() {
System.out.println("parent test...");
}
}
class Child15 extends Parent15 {
String name = "lisi";
@Override
void test() {
// System.out.println(this.name);
// System.out.println(super.name);
super.test();
System.out.println("child test...");
}
}
public class Java15_Object_1 {
public static void main(String[] args) {
// TODO 面向对象 - 重写
//CCC ccc = new CCC();
//DDD ddd = new DDD();
CCC ddd = new DDD();
// 一个对象能使用什么方法,取决于引用变量的类型
// 一个对象能使用什么属性,取决于引用变量的类型
// 一个对象的方法具体的使用(直接,间接)是需要看具体的对象的
// 一个对象的属性具体的使用是不需要看具体的对象的,属性在哪里声明在哪里使用
System.out.println(ddd.sum());
}
}
class CCC {
int i = 10;
int sum() {
return getI() + 10;
}
int getI() {
return i;
}
}
class DDD extends CCC {
int i = 20;
// int sum() {
// return i + 20;
// }
@Override
int getI() {
return i;
}
}
递归:
-
方法调用自身(阶乘等)
-
方法要有跳出的逻辑,注意 StackOverflowError 异常
-
调用自身时,传递的参数要有规律
public class Java16_Object_Recursion {
public static void main(String[] args) {
// TODO 面向对象 - 递归
// 所谓的递归:方法调用自身,称之为递归方法
// 1 + 3 + 5 + 7 + 9... + 19
// int result = computeAP( 10 );
// System.out.println(result);
// 阶乘 : 5! => (4,3,2,1) => 5 * 4 * 3 * 2 * 1
// 0的阶乘为1.
// 一个大于1的数的阶乘等于这个数乘以这个数减一的阶乘。
int result = computeFactorial(50000);
System.out.println(result);
// 1. 递归方法应该有跳出的逻辑:StackOverflowError
// 2. 调用自身时,传递的参数需要有规律
// 345345 + 4543534 + 32423 + 43423 + 32423
}
public static int computeFactorial(int num) {
if ( num <= 1 ) {
return 1;
} else {
return num + computeFactorial(num - 1);
}
}
public static int computeAP(int num) {
num = num % 2 == 0 ? num - 1 : num;
if ( num == 1 ) {
return 1;
} else {
return num + computeAP(num - 2);
}
}
}
访问权限:
public : 公共的,访问权限修饰符
Java的源码中,公共类只能有一个,而且必须和源码文件名相同
main方法:main方法是由JVM调用的,JVM调用时应该可以任意调用,而不用考虑权限问题。
Java中的访问权限主要分为4种:
-
private : 私有的, 同一个类中可以使用
-
(default) : 默认权限, 当不设定任何权限时,JVM会默认提供权限,包(路径)权限
-
protected : 受保护的权限, 子类可以访问
-
public : 公共的, 任意使用
-
private : 同类
-
default : 同类,同包(路径)
-
protected:同类,同包(路径),子类
-
public :公共的
-
所谓的访问权限,其实就是访问属性,方法的权力和限制。
内部类:
-
Java不允许外部类使用private, protected修饰
/所谓的外部类,就是在源码中直接声明的类
所谓的内部类,就是类中声明的类 -
内部类就当成外部类的属性使用即可
-
因为内部类可以看作外部类的属性,所以需要构建外部类对象才可以使用
public class Java17_Object_Access {
private String name;
public String username;
String sex;
public static void main(String[] args) {
// TODO 面向对象 - 访问权限
// public : 公共的,访问权限修饰符
// Java的源码中,公共类只能有一个,而且必须和源码文件名相同
// main方法:main方法是由JVM调用的,JVM调用时应该可以任意调用,而不用考虑权限问题。
// TODO Java中的访问权限主要分为4种:
// 1. private : 私有的, 同一个类中可以使用
// 2. (default) : 默认权限, 当不设定任何权限时,JVM会默认提供权限,包(路径)权限
// 3. protected : 受保护的权限, 子类可以访问
// 4. public : 公共的, 任意使用
User17 user = new User17();
// System.out.println(user.name);
// System.out.println(user.username);
// System.out.println(user.sex);
// System.out.println(user.age);
}
}
class User17 {
private String name;
public String username;
String sex;
protected int age;
void test() {
System.out.println(age);
System.out.println(name);
System.out.println(username);
}
}
class Child17 extends User17 {
@Override
void test() {
System.out.println(age);
}
}
public class Java17_Object_Access_1 {
public static void main(String[] args) {
// TODO 面向对象 - 访问权限
Person17 person = new Person17();
// private : 同类
// default : 同类,同包(路径)
// protected:同类,同包(路径),子类
// public :公共的
// 所谓的访问权限,其实就是访问属性,方法的权力和限制。
// 谁访问?Java17_Object_Access_1 -> super -> java.lang.Object
// 访问谁的?Person17 -> super -> java.lang.Object(clone)
// person.clone();
}
}
class Person17 {
void test() throws Exception {
clone();
}
}
public class Java18_Object {
public static void main(String[] args) {
// TODO 面向对象 - 外部类 - 内部类
// Java不允许外部类使用private, protected修饰
// 所谓的外部类,就是在源码中直接声明的类
// 所谓的内部类,就是类中声明的类
// 内部类就当成外部类的属性使用即可
// 因为内部类可以看作外部类的属性,所以需要构建外部类对象才可以使用
OuterClass outer = new OuterClass();
OuterClass.InnerClass innerClass = outer.new InnerClass();
}
}
class OuterClass {
public class InnerClass {
}
}
单列模式:
JVM默认给类提供的构造方法,其实就是公共的,无参的构造方法
- 类的创建过程复杂
- 类的对象消耗资源
public class Java19_Object {
public static void main(String[] args) {
// TODO 面向对象 - 单例模式
// JVM默认给类提供的构造方法,其实就是公共的,无参的构造方法
// 1. 类的创建过程复杂
// 2. 类的对象消耗资源
//User19 user = new User19();
User19 instance1 = User19.getInstance();
User19 instance2 = User19.getInstance();
User19 instance3 = User19.getInstance();
User19 instance4 = User19.getInstance();
User19 instance5 = User19.getInstance();
User19 instance6 = User19.getInstance();
System.out.println(instance1.equals(instance6));
}
}
class User19 {
private static User19 user19 = null;
private User19() {
}
public static User19 getInstance() {
if ( user19 == null ) {
user19 = new User19();
}
return user19;
}
}
final:
Java中提供了一种语法,可以在数据初始化后不被修改,使用关键字final
1.final可以修饰变量:变量的值一旦初始化后无法修改
2.final可以修饰属性:那么JVM无法自动进行初始化,需要自己进行初始化, 属性值不能发生变化
3.一般将final修饰的变量称之为常量,或者叫不可变变量
4.final可以修饰方法,这个方法不能被子类重写
5.final可以修饰类,这样类就没有子类了
6.final不可以修饰构造方法
7.final可以修改方法的参数,一旦修饰,参数就无法修改。
public class Java20_Object {
public static void main(String[] args) {
// TODO 面向对象
// Java中提供了一种语法,可以在数据初始化后不被修改,使用关键字final
// final可以修饰变量:变量的值一旦初始化后无法修改
// final可以修饰属性:那么JVM无法自动进行初始化,需要自己进行初始化, 属性值不能发生变化
// 一般将final修饰的变量称之为常量,或者叫不可变变量
// final可以修饰方法,这个方法不能被子类重写
// final可以修饰类,这样类就没有子类了
// final不可以修饰构造方法
// final可以修改方法的参数,一旦修饰,参数就无法修改。
final String name = "zhangsan";
//name = "wangwu";
//System.out.println(name);
//User20 user = new User20("wangwu");
User20 user = new User20();
//user.name = "zhangsan";
//System.out.println(user.name);
//user.name = "lisi";
//System.out.println(user.name);
}
}
final class User20 {
public User20() {
}
// public void test( final String name ) {
// name = "lisi";
// }
// public final String name;
// public User20(String name) {
// this.name = name;
// }
// public final void test() {
//
// }
}
//class Child20 extends User20 {
public void test() {
}
//}
抽象:
抽象类 : 不完整的类,就是抽象类
abstract class 类名
因为类不完整,所以无法直接构造对象
抽象方法 : 只有声明,没有实现的方法
abstract 返回值类型 方法名(参数)
分析问题:对象(具体) => 类(抽象)
编写代码:类(抽象) => 对象(具体)
- 如果一个类中含有抽象方法,那么这个类是抽象类
- 如果一个类是抽象类,它的方法不一定是抽象方法。
- 抽象类无法直接构建对象,但是可以通过子类间接构建对象
- 如果抽象类中含有抽象方法,那么子类继承抽象类,需要重写抽象方法,将方法补充完整
- abstract关键字不能和final同时使用
public class Java21_Object_Abstract {
public static void main(String[] args) {
// TODO 面向对象 - 抽象 - Abstract
// 抽象类 : 不完整的类,就是抽象类
// abstract class 类名
// 因为类不完整,所以无法直接构造对象
// 抽象方法 : 只有声明,没有实现的方法
// abstract 返回值类型 方法名(参数)
// 分析问题:对象(具体) => 类(抽象)
// 编写代码:类(抽象) => 对象(具体)
// 如果一个类中含有抽象方法,那么这个类是抽象类
// 如果一个类是抽象类,它的方法不一定是抽象方法。
// 抽象类无法直接构建对象,但是可以通过子类间接构建对象
// 如果抽象类中含有抽象方法,那么子类继承抽象类,需要重写抽象方法,将方法补充完整,
// abstract关键字不能和final同时使用
//Person21 person21 = new Person21();
Chinese21 c = new Chinese21();
c.eat();
}
}
abstract class Person21 {
public abstract void eat();
public void test() {
}
}
class Chinese21 extends Person21 {
@Override
public void eat() {
System.out.println("中国人使用筷子吃饭");
}
}
接口:
- 所谓的接口,可以简单理解为规则
- 基本语法 : interface 接口名称 { 规则属性,规则的行为 }
- 接口其实是抽象的,属性是静态的,行为是抽象的
- 规则的属性必须为固定值,而且不能修改。
- 属性和行为的访问权限必须为公共的。
- 接口和类是两个层面的东西
- 接口可以继承其他接口
- 类的对象需要遵循接口,在java中,这个遵循,称之为实现(implements),类需要实现接口,而且可以实现多个接口
public class Java22_Object {
public static void main(String[] args) {
// TODO 面向对象 - 接口
// 所谓的接口,可以简单理解为规则
// 基本语法 : interface 接口名称 { 规则属性,规则的行为 }
// 接口其实是抽象的
// 规则的属性必须为固定值,而且不能修改。
// 属性和行为的访问权限必须为公共的。
// 属性应该是静态的
// 行为应该是抽象的
// 接口和类是两个层面的东西
// 接口可以继承其他接口
// 类的对象需要遵循接口,在java中,这个遵循,称之为实现(implements),类需要实现接口,而且可以实现多个接口
Computer c = new Computer();
Light light = new Light();
c.usb1 = light;
Light light1 = new Light();
c.usb2 = light1;
c.powerSupply();
}
}
interface USBInterface {
}
interface USBSupply extends USBInterface {
public void powerSupply();
}
interface USBReceive extends USBInterface {
public void powerReceive();
}
class Computer implements USBSupply {
public USBReceive usb1;
public USBReceive usb2;
@Override
public void powerSupply() {
System.out.println("电脑提供能源");
usb1.powerReceive();
usb2.powerReceive();
}
}
class Light implements USBReceive {
@Override
public void powerReceive() {
System.out.println("电灯接收能源");
}
}
枚举类:
- 枚举是一个特殊的类,其中包含了一组特定的对象,这些对象不会发生改变, 一般都使用大写的标识符
- 枚举使用enum关键字使用
- 枚举类会将对象放置在最前面,那么和后面的语法需要使用分号隔开
- 枚举类不能创建对象,它的对象是在内部自行创建
public class Java23_Object_Enum {
public static void main(String[] args) {
// TODO 面向对象 - 枚举
// 枚举是一个特殊的类,其中包含了一组特定的对象,这些对象不会发生改变, 一般都使用大写的标识符,
// 枚举使用enum关键字使用
// 枚举类会将对象放置在最前面,那么和后面的语法需要使用分号隔开
// 枚举类不能创建对象,它的对象是在内部自行创建
System.out.println(City.BEIJING.name);
System.out.println(City.SHANGHAI.code);
System.out.println(MyCity.SHANGHAI.name);
System.out.println(MyCity.BEIJING.code);
}
}
class MyCity {
public String name;
public int code;
private MyCity(String name, int code) {
this.code = code;
this.name = name;
}
public static final MyCity BEIJING = new MyCity("北京", 1001);
public static final MyCity SHANGHAI = new MyCity("上海", 1002);
}
enum City {
BEIJING("北京", 1001), SHANGHAI("上海", 1002);
City( String name, int code ) {
this.code = code;
this.name = name;
}
public String name;
public int code;
}
匿名类:
- 在模型场合下,类的名字不重要,我们指向使用类中的方法或功能。那么此时我们可以采用特殊的语法:匿名类
- 所谓的匿名类,就是没有名字的类
public class Java24_Object {
public static void main(String[] args) {
// TODO 面向对象
// 在模型场合下,类的名字不重要,我们指向使用类中的方法或功能。那么此时我们可以采用特殊的语法:匿名类
// 所谓的匿名类,就是没有名字的类
Me me = new Me();
//me.sayHello( new Zhangsan() );
me.sayHello( new Person24() {
@Override
public String name() {
return "wangwu";
}
});
me.sayHello( new Person24() {
@Override
public String name() {
return "zhaoliu";
}
});
new Bird24().fly();
new Fly(){
@Override
public void fly() {
System.out.println("使用飞行器飞翔");
}
}.fly();
}
}
interface Fly {
public void fly();
}
class Bird24 implements Fly {
@Override
public void fly() {
System.out.println("使用翅膀飞翔");
}
}
abstract class Person24 {
public abstract String name();
}
class Me {
public void sayHello(Person24 person24) {
System.out.println("Hello " + person24.name());
}
}
class Zhangsan extends Person24 {
@Override
public String name() {
return "zhangsan";
}
}
class Lisi extends Person24 {
@Override
public String name() {
return "lisi";
}
}
Bean规范(pojo):
-
主要用于编写逻辑
-
主要用于建立数据模型(Bean)
Bean类得设计规范:Bean规范
1.类要求必须含有无参,公共得构造方法
2.属性必须私有化,然后提供公共得,set,get方法
public class Java25_Object {
public static void main(String[] args) {
// TODO 面向对象
// 1. 主要用于编写逻辑
// 2. 主要用于建立数据模型(Bean)
// TODO Bean类得设计规范:Bean规范
// 1. 类要求必须含有无参,公共得构造方法
// 2. 属性必须私有化,然后提供公共得,set,get方法
User25 user = new User25();
user.setAccount("admin");
user.setPassword("admin") ;
System.out.println(login(user));
}
public static boolean login( User25 user ) {
if ( user.getAccount().equals("admin") && user.getPassword().equals("admin") ) {
return true;
} else {
return false;
}
}
}
class User25 {
private String account;
private String password;
public void setAccount( String account ) {
this.account = account;
}
public void setPassword(String password) {
this.password = password;
}
public String getAccount() {
return account;
}
public String getPassword() {
return account;
}
}
作用域:
如果属性和(局部)变量名称相同,访问时不加修饰符,则优先访问变量
public class Java26_Object {
public static void main(String[] args) {
// TODO 面向对象 - 作用域
// User26 user = new User26();
User26.test();
}
}
class Person26 {
public static String name = "zhangsan";
}
class User26 extends Person26 {
public static String name = "lisi";
// public void test() {
// //String name = "wangwu";
//
// // 如果属性和(局部)变量的名称相同,访问时如果不加修饰符,那么优先访问变量
// System.out.println(super.name);
// System.out.println(name);
// }
public static void test() {
System.out.println(Person26.name);
}
}
Object 类:
-
toString():将对象转换成字符串,toString() 默认打印对象的内存地址,因此,为了能更直观地理解对象内容,可以重写这个方法
-
hashCode():获取对象的内存地址
-
equals():方法比较对象,默认比较内存地址
-
getClass():获取对象的类型信息
public class Java01_Object {
public static void main(String[] args) {
// TODO 常见类和对象
// java.lang.Object : 对象
Object obj = new Person();
// 讲对象转换成字符串。
// toString默认打印的就是对象的内存地址,所以,为了能够更直观理解对象的内容,所以可以重写这个方法
String s = obj.toString();
System.out.println(s);
// TODO 获取对象的内存地址
int i = obj.hashCode();
System.out.println(i);
// TODO 判断两个对象是否相等, 如果相等,那么返回true,否则返回false
// equals方法比较对象时,默认比较就是内存地址
Person otherPerson = new Person();
System.out.println(otherPerson.hashCode());
System.out.println(obj.equals(otherPerson));
// getClass获取对象的类型信息
Class<?> aClass = obj.getClass();
System.out.println(aClass.getSimpleName());
System.out.println(aClass.getPackageName());
}
}
class Person {
public String name = "zhangsan";
// @Override
// public String toString() {
// return "Person["+name+"]";
// }
@Override
public boolean equals(Object obj) {
return true;
}
}
class User extends Person {
}
2.7 数组
一维数组:
String[] nums = new String[3];
// //nums[0] = 1;
// for (Object num : nums) {
// System.out.println(num);
// }
// String[] names = {"zhangsan", "lisi", "wangwu"};
// System.out.println(names);
// for (String name : names) {
// System.out.println(name);
// }
// System.out.println(names.length);
二维数组:
// 二维数组
//String[][] names = {{"zhangsan", "lisi", "wangwu"}, {"zhangsan", "lisi"}, {"zhangsan"}};
// 标准的二维数组
String[][] namess = new String[3][3];
namess[0][1] = "zhangsan";
//System.out.println(namess[1][1]);
for ( int row = 0; row < 3; row++ ) {
for ( int col = 0; col < 3; col++ ) {
System.out.print(namess[row][col] + " ");
}
System.out.println();
}
九层妖塔用数组实现:
public class Java03_Object_Test {
public static void main(String[] args) {
// TODO 常见类和对象
// 二维数组
/*
九层妖塔
*
***
*****
*******
*/
// 1 => 1
// 2 => 3
// 3 => 5
// 4 => 7
// 1 => 0
// 2 => 1
// 3 => 2
// 4 => 3
// 0 => 8
// 1 => 789
// 2 => 678910
int row = 9;
int col = 2 * (row - 1) + 1;
String[][] nineTower = new String[row][col];
for ( int i = 0; i < row; i++ ) {
for ( int j = 0; j < col; j++ ) {
if ( j >= ( row - 1 ) - i && j <= ( row - 1 ) + i ) {
nineTower[i][j] = "*";
} else {
nineTower[i][j] = " ";
}
}
}
for ( int i = 0; i < row; i++ ) {
for ( int j = 0; j < col; j++ ) {
System.out.print(nineTower[i][j]);
}
System.out.println();
}
}
}
查找与排序:
1.冒泡排序:将当前数组的最大值放最后
public class Java03_Object_Test_1 {
public static void main(String[] args) {
// TODO 常见类和对象
// 数组
int[] nums = {1,4,3,5,2};
// TODO 希望获取到的数据,1,2,3,4,5
// 简化需求:将数组中的最大值放置数组的最后
for ( int j = 0; j < nums.length; j++ ) {
for ( int i = 0; i < nums.length - j - 1; i++ ) {
int num1 = nums[i];
int num2 = nums[i+1];
if ( num1 > num2 ) {
// 左边的数据大于右边的数据,应该交互位置
nums[i] = num2;
nums[i+1] = num1;
}
}
}
for (int num : nums) {
System.out.println(num);
}
}
}
2.选择排序:先选择一个值作为最大值,再挨个比较,最后找到最大值索引并交换
public class Java03_Object_Test_2 {
public static void main(String[] args) {
// TODO 常见类和对象
// 数组 - 选择排序
int[] nums = {1,4,3,5,2};
for ( int j = 0; j < nums.length; j++ ) {
int maxIndex = 0;
for ( int i = 1; i < nums.length - j; i++ ) {
if ( nums[i] > nums[maxIndex] ) {
maxIndex = i;
}
}
int num1 = nums[nums.length-j-1];
int num2 = nums[maxIndex];
nums[maxIndex] = num1;
nums[nums.length-j-1] = num2;
}
for (int num : nums) {
System.out.println(num);
}
}
}
二分查找:适用于有序数据
public class Java03_Object_Test_3 {
public static void main(String[] args) {
// TODO 常见类和对象
// 数组 - 数据查询 - 二分查找法
int[] nums = {1,2,3,4,5,6,7};
// 查询目标
int targetNum = 6;
int start = 0;
int end = nums.length - 1;
int middle = 0;
while ( start <= end ) {
middle = (start + end) / 2;
if ( nums[middle] > targetNum ) {
end = middle - 1;
} else if ( nums[middle] < targetNum ) {
start = middle + 1;
} else {
break;
}
}
System.out.println("数据在数组的位置:" + middle);
}
}
2.8 字符串
-
连续字符组成的数据整体
-
字符串、字符、字节的关系
public class Java04_Object_String {
public static void main(String[] args) throws Exception {
// TODO 常见类和对象
// TODO 字符串连续字符组成形成的数据整体
// java.lang.String
// 字符串,字符,字节的关系
// String name = "zhangsan";
// String name2 = "zhangsan";
// String name3 = "zhangsan";
// String name4 = "zhangsan";
// String name1 = new String("zhangsan");
// char[] cs = {'a', '中', '国'};
// byte[] bs = {-28,-72,-83,-27,-101,-67};
//
// String s = new String(cs);
// String s1 = new String(bs, "UTF-8");
//
// System.out.println(s);
// System.out.println(s1);
String s = "\"";
// 转义字符:\" => 文字内容的双引号
// \', \t, \n, \\
System.out.println(s);
System.out.println("\'");
System.out.println("a\tb");
System.out.println("c\nd");
System.out.println("e\\f");
}
}
- 字符串的拼接、比较
// TODO 拼接:将多个字符串连接在一起
String s = "a" + "b"; // "ab"
String s1 = "ab";
String s2 = "abc" + 1 + 2; // abc12
String s3 = 1 + "abc" + 2; // 1abc2
String s4 = (1 + 2) + "abc"; // 3abc
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
System.out.println(s1.concat("abc"));
// TODO 字符串的比较
String a = "a";
String b = "A";
// 相等
System.out.println(a.equals(b));
// 忽略大小写的相等
System.out.println(a.equalsIgnoreCase(b));
// i = 正数,a > b
// i = 负数,a < b
// i = 0, a = b
byte b1 = (byte)'A';
byte b2 = (byte)'a';
System.out.println("A = " + b1);
System.out.println("a = " + b2);
int i = a.compareTo(b);
System.out.println(i);
// 忽略大小写的比较
System.out.println(a.compareToIgnoreCase(b));
- 字符串的截断 substring(begin, end)、trim()
// TODO 字符串的截断操作 : 截取字符串的操作
String s = " Hello World ";
// 子字符串
// substring方法用于截取字符串,需要传递两个参数,
// 第一个参数表示截取字符串的起始位置(索引,包含)
// 第二个参数表示截取字符串的结束位置(索引,不包含)
System.out.println(s.substring(0, 3));
System.out.println(s.substring(0, "Hello".length()));
System.out.println(s.substring(6, s.length()));
//substring方法如果只传递一个参数,那么就表示从指定位置开始截取字符串,然后截取到最后
System.out.println(s.substring(6));
// 分解字符串 :根据指定的规则对字符串进行分解。可以将一个完整的字符串,分解成几个部分。
String[] s1 = s.split(",");
System.out.println(s1.length);
for (String s2 : s1) {
System.out.println(s2);
}
// TODO trim : 去掉字符串的首尾空格的意思
System.out.println("!" + s.trim() + "!");
- 字符串的替换 replace()、replaceAll()
// TODO 字符串的替换。
String s = "Hello World zhangsan"; // Hello Java Java
// 替换
System.out.println(s.replace("World zhangsan", "Java"));
// replaceAll按照指定的规则进行替换
System.out.println(s.replaceAll("World|zhangsan", "Java"));
- 大小写转换、查找 indexOf()、contains()
String s = "Hello World";
System.out.println(s.toLowerCase());
System.out.println(s.toUpperCase());
String className = "user"; // u + ser
String s1 = className.substring(0, 1); // u
String s2 = className.substring(1); // ser
System.out.println(s1.toUpperCase() + s2);
// TODO 字符串的查找
String s = " ";
//char[] chars = s.toCharArray();
//byte[] bytes = s.getBytes("UTF-8");
// charAt可以传递索引定位字符串中指定位置的字符
//System.out.println(s.charAt(1));
// indexof方法用于获取数据在字符串中第一次出现的位置。
//System.out.println(s.indexOf("World"));
// lastIndexOf方法用于获取数据在字符串中最后一次出现的位置。
//System.out.println(s.lastIndexOf("World"));
// 是否包含指定的字符串,返回布尔类型
//System.out.println(s.contains("Hello123"));
// 判断字符串是否以指定的数据开头,返回布尔类型
//System.out.println(s.startsWith("Hello"));
// 判断字符串是否以指定的数据结尾,返回布尔类型
//System.out.println(s.endsWith("World"));
// 判断字符串是否为空,空格其实是一个特殊的字符,所以看不到,但是不为空。
System.out.println(s.isEmpty());
- StringBuilder 构建字符串,优化字符串操作效率,底层用数组实现字符拼接,而不是构建大量字符串
public class Java04_Object_String_2 {
public static void main(String[] args) throws Exception {
// TODO 常见类和对象
// StringBuilder : 构建字符串
// concat
// String s = "";
// for ( int i = 0; i < 100; i++ ) {
// s = s + i; // 01234....
// }
// System.out.println(s);
// "a" + "b" => "ab"
// StringBuilder s = new StringBuilder();
// for ( int i = 0; i < 100; i++ ) {
// s.append(i);
// }
// System.out.println(s.toString());
StringBuilder s = new StringBuilder();
s.append("abc");
System.out.println(s.toString());
System.out.println(s.length());
System.out.println(s.reverse()); // 反转字符串
System.out.println(s.insert(1, "d"));
}
}
2.9 包装类
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
自动装箱和自动拆箱
// 自动装箱
Integer i1 = Integer.valueOf(i);
// 自动拆箱
int i2 = i1.intValue();
public class Java05_Object_Datatype {
public static void main(String[] args) throws Exception {
// TODO 常见类和对象
// byte short int long
// float double
// char
// boolean
// TODO 包装类
// Byte b = null;
// Short s = null;
// Integer i = null;
// Long lon = null;
// Float f = null;
// Double d = null;
// Character c = null;
// Boolean bln = null;
int i = 10;
//Integer i1 = new Integer(i);
// TODO 将基本数据类型转换为包装类型
// 自动装箱
Integer i1 = Integer.valueOf(i);
// Integer i1 = i;
// 自动拆箱
int i2 = i1.intValue();
// int i2 = i1;
}
}
3.0 日历类和日期类
Date : 日期类
Calendar : 日历类
Java格式化日期格式:
y (Y) -> 年 -> yyyy
m (M) -> MM : 月份,mm:分钟
d (D) -> dd : 一个月中的日期,D:一年中的日期
h (H) -> h : 12进制, HH:24进制
s (S) -> s : 秒,S :毫秒
import java.text.SimpleDateFormat;
import java.util.Date;
public class Java06_Object_Date {
public static void main(String[] args) throws Exception {
// TODO 常见类和对象
// Date : 日期类
// 时间戳 : 毫秒
//System.out.println(System.currentTimeMillis());
// Date : 日期类
// Calendar : 日历类
Date d = new Date();
System.out.println(d);
// Java格式化日期格式:
// y (Y) -> 年 -> yyyy
// m (M) -> MM : 月份,mm:分钟
// d (D) -> dd : 一个月中的日期,D:一年中的日期
// h (H) -> h : 12进制, HH:24进制
// s (S) -> s : 秒,S :毫秒
// Date -> String
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateFormatString = sdf.format(d);
System.out.println(dateFormatString);
// String -> Date
String dateString = "2022-06-01";
Date parseDate = sdf.parse(dateString);
System.out.println(parseDate);
// 根据时间戳构建指定的日期对象。
//d.setTime(System.currentTimeMillis());
// 获取时间戳
//d.getTime();
System.out.println(parseDate.before(d));
System.out.println(parseDate.after(d));
}
}
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class Java07_Object_Date {
public static void main(String[] args) throws Exception {
// TODO 常见类和对象
// 日历类
Calendar instance = Calendar.getInstance();
//System.out.println(instance);
System.out.println(instance.get(Calendar.YEAR));
System.out.println(instance.get(Calendar.MONTH));
System.out.println(instance.get(Calendar.DATE));
//System.out.println(instance.get(Calendar.DAY));
instance.setTime(new Date());
instance.add(Calendar.YEAR, -1);
}
}
练习打印日历
import java.util.Calendar;
import java.util.Date;
public class Java07_Object_Date_Test {
public static void main(String[] args) throws Exception {
// TODO 常见类和对象
// 打印当前日历
System.out.println("周一\t周二\t周三\t周四\t周五\t周六\t周日");
// 获取当前日期的日历对象
Calendar firstDate = Calendar.getInstance();
// 把日历对象设定位当前月的第一天 : 10-01
firstDate.set(Calendar.DAY_OF_MONTH, 1);
// 获取当前月最大的日期 : 31
int maxDay = firstDate.getMaximum(Calendar.DAY_OF_MONTH);
for ( int i = 0; i < maxDay; i++ ) {
// 当前日期是周几
int weekX = firstDate.get(Calendar.DAY_OF_WEEK);
// 当前日期是几号
int monthY = firstDate.get(Calendar.DAY_OF_MONTH);
if ( i == 0 ) {
if (weekX == Calendar.SUNDAY) {
for ( int j = 0; j < 6; j++ ) {
System.out.print("\t");
}
System.out.println(monthY);
} else {
// 周日是1,周一是2...周六是7
for ( int j = 0; j < weekX - 2; j++ ) {
System.out.print("\t");
}
System.out.print(monthY);
System.out.print("\t");
}
} else {
// 不是一号的场合
if ( weekX == Calendar.SUNDAY ) {
System.out.println(monthY);
} else {
System.out.print(monthY);
System.out.print("\t");
}
}
// 打印日历后,应该增加一天
firstDate.add(Calendar.DATE, 1);
}
}
}
3.1 工具类
举例:字符串工具类
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
public class Java08_Object_Util {
public static void main(String[] args) throws Exception {
System.out.println(StringUtil.isEmpty(null));
System.out.println(StringUtil.isEmpty(""));
System.out.println(StringUtil.isEmpty(" "));
System.out.println(StringUtil.isEmpty("abc"));
System.out.println(StringUtil.makeString());
System.out.println(StringUtil.makeString("abcdedf123456", 6));
System.out.println(StringUtil.formatDate(new Date(), "yyyy-MM-dd"));
System.out.println(StringUtil.parseDate("2020-06-14", "yyyy-MM-dd"));
}
}
// 字符串工具类
// 1. 工具类不应该创建对象才能使用,也就意味着,可以直接使用类中的属性和方法,一般都声明为静态的。
// 2. 工具类对外提供的属性或方法都应该是公共的。
// 3. 为了使用者开发方便,应该尽量提供丰富的方法和属性
class StringUtil {
// 非空判断
public static boolean isEmpty(String str) {
// // 如果字符串为null,为空
// if ( str == null ) {
// return true;
// }
// // 如果字符串为空字符串,为空
// if ( "".equals(str) ) {
// return true;
// }
// // 如果字符串全都是空格,也为空
// if ( "".equals(str.trim()) ) {
// return true;
// }
if ( str == null || "".equals(str.trim()) ) {
return true;
}
return false;
}
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
// 生成随机字符串
public static String makeString() {
return UUID.randomUUID().toString();
}
public static String makeString(String from, int len) {
if ( len < 1 ) {
return "";
} else {
char[] chars = from.toCharArray();
StringBuilder str = new StringBuilder();
for ( int i = 0; i < len; i++ ) {
Random random = new Random();
int j = random.nextInt(chars.length);
char c = chars[j];
str.append(c);
}
return str.toString();
}
}
// 转换字符串 : ISO8859-1 => str => UTF-8
public static String transform( String source, String encodeFrom, String encodeTo ) throws Exception {
byte[] bytes = source.getBytes(encodeFrom);
return new String(bytes, encodeTo);
}
public static Date parseDate( String dateString, String format ) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.parse(dateString);
}
public static String formatDate( Date date, String format ) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
}
}
3.2 比较
基本数据类型,双等号比较数值
引用数据类型,双等号比较变量的内存地址
包装类型用equals
import java.util.Calendar;
public class Java09_Object {
public static void main(String[] args) throws Exception {
// TODO 常见类和对象
// 等于
// 基本数据类型,双等号比较数值
// int i = 10;
// int j = 10;
// System.out.println(i == j);
// double d = 10.0;
// System.out.println(i == d);
// // 引用数据类型,双等号比较变量的内存地址
// String s = "abc"; // 字符串常量池
// String s1 = "abc";
// String s2 = new String("abc");
// System.out.println(s == s1);
// System.out.println(s == s2);
// System.out.println(s.equals(s2));
//
// User9 user1 = new User9();
// User9 user2 = new User9();
//
// System.out.println(user1 == user2);
// System.out.println(user1.equals(user2));
// 包装类型
// int => Integer => JVM为了操作方便,简化了很多操作
// Integer缓存:-128 ~ 127
Integer i1 = Integer.valueOf(-129);
Integer i2 = Integer.valueOf(-129);
// System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
}
}
class User9 {
@Override
public int hashCode() {
return 1;
}
@Override
public boolean equals(Object obj) {
return true;
}
}
3.3 异常
1 可以通过代码恢复正常逻辑的异常,称之为运行期异常。(RuntimeException)
//java.lang.StackOverflowError
//递归
//Error : 错误
//test();
//java.lang.NullPointerException
// 异常 : Exception
2 不可以通过代码恢复正常逻辑的异常,称之为编译期期异常(Exception)
类型转换错误
String s = "123";
Integer i = (Integer)s;
异常处理语法
try :尝试
catch : 捕捉
捕捉多个异常的时候,需要先捕捉范围小的异常,然后再捕捉范围大的异常
finally : 最终
public class Java02_Exception {
public static void main(String[] args) {
// TODO 异常
/*
异常处理语法:
TODO try :尝试
TODO catch : 捕捉
捕捉多个异常的时候,需要先捕捉范围小的异常,然后再捕捉范围大的异常
TODO finally : 最终
try {
可能会出现异常的代码
如果出现异常,那么JVM会将异常进行封装,形成一个具体的异常类,然后将这个异常抛出
所有的异常对象都可以被抛出
} catch ( 抛出的异常对象 对象引用 ) {
异常的解决方案
} catch () {
} finally {
最终执行的代码逻辑
}
*/
int i = 0;
int j = 0;
try {
j = 10 / i;
} catch (ArithmeticException e) {
//e.getMessage() // 错误的消息
//e.getCause()
//e.printStackTrace();
i = 10;
j = 10 / i;
} finally {
System.out.println("最终执行的代码");
}
System.out.println(j);
}
}
算术异常、空指针异常(成员属性或方法为空)
public class Java03_Exception {
public static void main(String[] args) {
// TODO 异常
// 1. 除数为0的算术异常:java.lang.ArithmeticException
// 运行期异常
// int i = 0;
// if ( i != 0 ) {
// int j = 10 / i;
// }
// 2 : 空指针异常 : java.lang.NullPointerException
// 调用了一个为空(null)对象的成员属性或成员方法时,就会发生异常
User3 user = null;
// if ( user != null ) {
// System.out.println(user.toString());
// }
try {
System.out.println(user.toString());
// System.out.println(user.name); 静态的属性跟对象没有关系
} catch (NullPointerException e) {
System.out.println("对象为空,需要分析数据为空的原因");
}
}
}
class User3 {
public static String name = "zhangsan";
}
索引越界、字符串索引越界
索引越界 : ArrayIndexOutOfBoundsException
字符串索引越界:StringIndexOutOfBoundsException
public class Java04_Exception {
public static void main(String[] args) {
// TODO 异常
// 3. 索引越界 : ArrayIndexOutOfBoundsException
String[] names = new String[3];
names[0] = "zhangsan";
names[1] = "lisi";
names[2] = "wangwu";
if ( names.length == 4 ) {
names[3] = "zhaoliu";
}
for ( int i = 0; i < names.length; i++ ) {
System.out.println(names[i]);
}
// 4. 字符串索引越界:StringIndexOutOfBoundsException
String s = "abc";
//System.out.println(s.charAt(3));
System.out.println(s.substring(4));
}
}
格式化异常、类型转换错误
格式化异常:NumberFormatException
类型转换错误:java.lang.ClassCastException
public class Java05_Exception {
public static void main(String[] args) {
// TODO 异常
// 5. 格式化异常:NumberFormatException
// String s = "a123";
// Integer i = Integer.parseInt(s);
//
// System.out.println(i);
// 6 类型转换错误:java.lang.ClassCastException
Object obj = new User5();
if ( obj instanceof Emp5 ) {
Emp5 emp = (Emp5)obj;
}
}
}
class User5 {
}
class Emp5 {
}
可以创建异常对象,并提供异常信息
可以主动抛出异常,使用关键字throw
如果方法抛出异常,那么可以使用throws关键字明确方法会抛出异常
public class Java07_Exception {
public static void main(String[] args) throws Exception {
// TODO 异常
// 可以创建异常对象,并提供异常信息
// 可以主动抛出异常,使用关键字throw
// 如果方法抛出异常,那么可以使用throws关键字明确方法会抛出异常
int i = 10;
int j = 0;
test(i, j);
}
public static void test( int i, int j ) throws Exception {
try {
System.out.println(i / j);
} catch (ArithmeticException e) {
throw new Exception("除数为0");
}
}
}
自定义异常,准确描述错误场景
public class Java08_Exception {
public static void main(String[] args) throws Exception {
// TODO 异常
User8 user = new User8();
int i = 10;
int j = 0;
try {
user.test(i, j);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class User8 {
// 如果方法中可能会出现问题,那么需要提前声明,告诉其他人,我的方法可能会出问题。
// 此时需要使用关键字throws
// 如果程序中需要手动抛出异常对象,那么需要使用throw关键字,然后new出异常对象
public void test( int i, int j ) throws Exception {
try {
System.out.println( i / j);
} catch (ArithmeticException e) {
throw new Exception();
}
}
}
3 进阶语法
3.1集合
Java中的集合是一个名词,数据的一种容器,用于容纳数据并且提供了完整的集合框架
问题:什么时候需要一个容纳数据的容器,也就是集合对象?
Java集合框架中就包含了对不确定个数的数据处理的集合类,确定个数可以用数组
问题:如果只是为了容纳数据,可以是直接使用数组,为什么要学习集合?
数组使用起来不方便。在数据个数不确定的场合,数组使用起来不是很方便
总结:对不确定的有关系的数据进行相同的逻辑处理的场合,使用集合是一个不错的选择
根据数据的不同,Java的集合分为2大体系:
- 单一数据体系 : Collection接口定义了相关的规则
- 成对出现的数据体系 : Map接口定义了相关的规则
所谓的成对的数据,就是2个数据有关系,可以根据第一个数据关联到第二个数据
也称之为键值对数据 ,(123123, zhangsan) => (key, value)
Collection接口:
常用的子接口:
- List :按照插入顺序保存数据,数据可以重复的,具体的实现类: ArrayList, LinkedList
- Set : 集,无序保存,数据不能重复,具体的实现类 HashSet
- Queue : 队列,具体的实现类:ArrayBlockingQueue
Map接口: 具体的实现 : HashMap, Hashtable
List接口:
ArrayList : Array + List 存储的数据可以重复 内部采用数据存取数据
List : 列表,清单 按照数据插入顺序进行存储
Array : 数组,阵列
1.创建第一个集合对象:new ArrayList();
- 不需要传递构造参数,直接new就可以,底层数组为空数组
- 构造参数需要传递一个int类型的值,用于设定底层数组的长度
- 构造参数需要传递一个Collection集合类型的值,用于将其他集合中的数据放置在当前集合中
ArrayList list = new ArrayList();
2.增加数据:add()
- add方法可以增加数据,只要将数据作为参数传递到add方法即可
- 添加数据时,如果集合中没有任何的数据,那么底层会创建长度为10的数组
list.add(" ");
3.访问集合中的数据
获取集合中数据的条数:list.size()
获取指定位置的数据,可以采用索引的方式:list.get(1)
遍历集合中的数据:
for ( int i = 0; i < list.size(); i++ ) {
System.out.println("集合中的数据:" + list.get(i));
}
如果循环遍历集合数据时,不关心数据的位置,那么可以采用特殊的for循环:
for ( Object obj : list ) {
System.out.println("集合中的数据:" + obj);
}
4.修改数据
将指定位置的数据进行修改,set方法需要传递2个参数,第一个参数表示数据的位置,第二个参数修改的值。
方法会返回结果,这个结果就是更新前的值
Object removeVal = list.remove(1);
System.out.println("删除的值:" + removeVal);
5.打印集合对象
System.out.println(list);
ArrayList的常用方法:
import java.util.ArrayList;
public class Java04_Collection_List_ArrayList {
public static void main(String[] args) {
// TODO 集合 - Collection - List
// ArrayList的常用方法
ArrayList list = new ArrayList();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhangsan");
list.add("zhangsan");
// add方法可以传递2个参数的,第一个参数表示数据增加的位置(索引),第二个参数表示数据
list.add(1, "zhaoliu");
ArrayList otherList = new ArrayList();
otherList.add("1");
otherList.add("2");
otherList.add("3");
list.addAll( otherList );
// size方法表示集合内部数据的数量
System.out.println(list.size());
//清空集合中的数据
list.clear();
//删除指定集合中的数据
list.removeAll(otherList);
//判断集合中的数据是否为空
System.out.println(list.isEmpty());
//用于判断集合中是否存在某条数据,返回布尔类型的值
System.out.println(list.contains("zhangsan123"));
//用于获取数据在索引中的第一个位置,如果数据不存在,那么返回-1
System.out.println(list.indexOf("zhangsan123"));
System.out.println(list.indexOf("zhangsan"));
System.out.println(list.lastIndexOf("zhangsan"));
Object[] objects = list.toArray();
// 复制新集合
Object clone = list.clone();
ArrayList list1 = (ArrayList)clone;
System.out.println(list);
System.out.println(list1);
}
}
LinkedList : Linked(连接) + List
1.创建一个集合对象:new LinkedList();
2.增加数据:
list.add("wangwu");
list.addFirst("lisi");//在链表的首位置插入
list.addLast("zhangsan");//在链表的末位置插入
list.add(1, "wangwu");//在指定位置插入数据
3.获取数据:
list.getFirst()
list.getLast()
4.遍历数据:
System.out.println(list.get(1));
for ( int i = 0; i < list.size(); i++ ) {
//System.out.println(list.get(i));
}
for ( Object obj : list ) {
System.out.println(obj);
}
5.修改数据:
list.set(1, "zhaoliu");
6.删除数据:
list.remove("zhangsan");
7.打印集合数据:
System.out.println(list);
常用方法:
import java.util.LinkedList;
public class Java05_Collection_List_LinkedList_1 {
public static void main(String[] args) {
// TODO 集合 - Collection - List
// LinkedList : Linked(连接) + List
// 构建集合对象
LinkedList list = new LinkedList();
// 追加数据
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
// // 想指定的位置增加数据
list.add(1, "zhaoliu");
list.addFirst("1");
list.addLast("2");
LinkedList list1 = new LinkedList();
list1.add("zhangsan1");
list1.add("lisi2");
list1.add("wangwu3");
list.addAll(list1);
System.out.println(list.remove("1"));
System.out.println(list.remove()); // 删除第一个
list.removeFirst();
list.removeLast();
list.remove(1);
System.out.println(list.size());
System.out.println(list.isEmpty());
list.clear();
list.contains("1");
list.element(); // 获取第一个数据
list.indexOf("");
list.lastIndexOf("");
list.push("aaa"); // 添加数据
System.out.println(list.pop()); // 弹出数据
System.out.println(list);
}
}
泛型:
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型只在编译阶段有效。看下面的代码:
List<String> stringArrayList = new ArrayList<String>();
List<Integer> integerArrayList = new ArrayList<Integer>();
Class classStringArrayList = stringArrayList.getClass();
Class classIntegerArrayList = integerArrayList.getClass();
if(classStringArrayList.equals(classIntegerArrayList)){
Log.d("泛型测试","类型相同");
}
//输出结果:D/泛型测试: 类型相同。
通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
import java.util.ArrayList;
public class Java06_Collection {
public static void main(String[] args) {
// TODO 集合 - Collection
// 泛型语法
ArrayList<Person6> list = new ArrayList();
// Person6 user = new User6(); 多态
// user.testUser();
// user.testPerson();
Person6 person = new Person6();
User6 user = new User6();
//把两个对象放在集合当中 集合没有约束类型所以什么都能放
list.add(person);
// list.add(user);
//list.remove(0);
// 从集合中获取的对象类型为Object
// Object o = list.get(0);
// // 如果想要执行对象的方法,那么需要进行强制类型转换
// if ( o instanceof Person6 ) { //判断对象类型为Person6
// Person6 p = (Person6)o;
// p.testPerson();
// }
Person6 person6 = list.get(0);
person6.testPerson();
}
}
class Person6 {
public void testPerson() {
System.out.println("person...");
}
}
class User6 {
public void testUser() {
System.out.println("user...");
}
}
import java.util.ArrayList;
public class Java07_Collection_Generic {
public static void main(String[] args) {
// TODO 集合 - Collection
// 泛型语法
// TODO 泛型和类型的区别
// 有时,也把泛型称之为类型参数
MyContainer<User7> myContainer = new MyContainer();
//myContainer.data = new Object();
// 类型存在多态的使用方式,但是泛型没有多态的概念
test(myContainer);
}
public static void test(MyContainer<User7> myContainer) {
System.out.println(myContainer);
}
}
// TODO 容器类
class MyContainer<C> {
public C data;
}
class User7 {
}
比较器:
import java.util.ArrayList;
import java.util.Comparator;
public class Java08_Collection_Sort {
public static void main(String[] args) {
// TODO 集合 - Collection - List
// Sort排序
ArrayList list = new ArrayList();
list.add(1);
list.add(3);
list.add(2);
// 1,3,2
// 1,2,3
// List对象进行排序,需要传递一个实现了比较器接口的对象
list.sort(new NumberComparator());
System.out.println(list);
}
}
class NumberComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
if ( o1 < o2 ) {//表示升序
return 1;
} else if (o1.equals(o2)) {
return 0;
} else {//表示降序
return -1;
}
}
}
如果根据索引查询数据 ArrayList更快,如果没有索引两者差别不大
**HashSet:**不能存储重复数据
HashSet = Hash + Set
Hash : 哈希算法,散列算法
import java.util.ArrayList;
import java.util.HashSet;
public class Java09_Collection_Set {
public static void main(String[] args) {
// TODO 集合 - Collection - Set
// HashSet : Hash + Set
// Hash : 哈希算法,散列算法
// ArrayList : 数组
// LinkedList :
HashSet set = new HashSet();
// TODo 增加数据
set.add("zhangsan");
set.add("zhangsan");
set.add("lisi");
set.add("wangwu");
// TODo 修改数据
// TODo 删除数据
//set.remove("wangwu");
// TODo 查询数据
for (Object o : set) {
System.out.println(o);
}
System.out.println(set);
}
}
常用方法:
import java.util.ArrayList;
import java.util.HashSet;
public class Java09_Collection_Set_1 {
public static void main(String[] args) {
// TODO 集合 - Collection - Set
HashSet set = new HashSet();
ArrayList list = new ArrayList();
list.add("zhangsan");
list.add("lisi");
list.add("wamngwu");
set.addAll(list);
Object[] objects = set.toArray();
System.out.println(set.isEmpty());
//set.clear();
set.contains("zhangsan");
System.out.println(set.size());
Object clone = set.clone();
System.out.println(clone);
System.out.println(set);
}
}
重复数据处理:
import java.util.ArrayList;
import java.util.HashSet;
public class Java09_Collection_Set_2 {
public static void main(String[] args) {
// TODO 集合 - Collection - Set
// HashSet 底层数据结构为 数组 + 链表
HashSet set = new HashSet();
User9 user1 = new User9();
user1.id = 1001;
user1.name = "zhangsan";
System.out.println(user1.hashCode());
User9 user2 = new User9();
user2.id = 1001;
user2.name = "wangwu";
System.out.println(user2.hashCode());
User9 user3 = new User9();
user3.id = 1002;
user3.name = "lisi";
set.add(user1);
set.add(user2);
set.add(user3);
System.out.println(set);
}
}
class User9 {
public int id;
public String name;
@Override
// 类似于内存地址
public int hashCode() {
return id;
}
@Override
// 判断两个对象的属性是否完全相同
public boolean equals(Object obj) {
if ( obj instanceof User9 ) {
User9 otherUser = (User9)obj;
if ( otherUser.id == this.id ) {
if ( otherUser.name.equals(this.name) ) {
return true;
}
}
return false;
} else {
return false;
}
}
@Override
public String toString() {
return "User["+id+", "+name+"]";
}
}
Queue:队列
ArrayBlockingQueue : Array + Blocking(阻塞,堵住) + Queue
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
public class Java10_Collection_Queue {
public static void main(String[] args) throws Exception {
// TODO 集合 - Collection - Queue
// ArrayBlockingQueue : Array + Blocking(阻塞,堵住) + Queue
ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
// add方法如果增加数据增加不了,直接发生错误。
// queue.add("zhangsan");
// queue.add("lisi");
// queue.add("wangwu");
// queue.add("zhaoliu"); // 发生错误,Queue full
// queue.put("zhangsan");
// System.out.println("第一个人挂号");
// queue.put("lisi");
// System.out.println("第二个人挂号");
// queue.put("wangwu");
// System.out.println("第三个人挂号");
// queue.put("zhaoliu"); //这个阻塞了
// System.out.println("第四个人挂号");
boolean zhangsan = queue.offer("zhangsan");
System.out.println(zhangsan);
boolean lisi = queue.offer("lisi");
System.out.println(lisi);
boolean wangwu = queue.offer("wangwu");
System.out.println(wangwu);
boolean zhaoliu = queue.offer("zhaoliu");//false
System.out.println(zhaoliu);
// System.out.println(queue.poll()); //往外取数据
// System.out.println(queue.poll());
// System.out.println(queue.poll());
// System.out.println(queue.poll());//返回了null
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());//后面的程序不执行了,但还在跑,处于阻塞态
// queue.size()
// queue.isEmpty()
// queue.clear();
// queue.contains()
System.out.println(queue);
}
}
HashMap : 数据存储是无序
HashMap =Hash + Map
HashMap map = new HashMap();
1.添加数据:put
2.修改数据:put方法也可以修改数据,返回值就是被修改的值
map.put("zhangsan", "1");
System.out.println(map.put("zhangsan", "4"));
map.put("lisi", "2");
map.put("wangwu", "3");
3.查询数据:
map.get("zhangsan")
4.删除数据:
map.remove("zhangsan");
5.打印数据:
System.out.println(map);
常用方法:
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Java11_Collection_Map_1 {
public static void main(String[] args) throws Exception {
// TODO 集合 - Map
HashMap<String, String> map = new HashMap();
// 添加数据
// 修改数据
// map.put("a", "0");
// Object oldVal = map.put("a", "1");
// //System.out.println(oldVal);
// // 添加数据
// map.putIfAbsent("b", "2");//
// map.putIfAbsent("b", "3");//如果里面有数据了 就不覆盖了
//
// Object b = map.replace("c", "4");//真正的修改数据的方法 没有就不修改也没添加
// System.out.println(b);
map.clear();
map.put("zhangsan", "1");
map.put("lisi", "2");
map.put("wangwu", "3");
// TODO 获取map集合中所有的key
// Set set = map.keySet();
// for (Object k : set) {
// System.out.println(map.get(k));
// }
// System.out.println(map.containsKey("zhangsan"));
//
// Collection values = map.values();
// map.containsValue("1")
//
// System.out.println(map);
// TODO 获取键值对对象
// Set<Map.Entry<String, String>> entries = map.entrySet();
// for (Map.Entry<String, String> entry : entries) {
// System.out.println(entry.getKey() + "=" + entry.getValue());
// }
// map.remove("zhangsan");
map.remove("zhangsan", "1");
// map.size()
// map.isEmpty()
// map.clear();
// map.clone()
System.out.println(map);
}
}
Hashtable:
- 实现方式不一样的 : 继承父类不一样
- 底层结构的容量不同: HashMap(16), Hashtable(11)
- HashMap的K,V都可以为null, Hashtable的K, V不能是null
- HashMap的数据定位采用的是Hash算法,但是Hashtable采用的就是hashcode
- HashMap的性能较高,但是Hashtable较低
import java.util.HashMap;
import java.util.Hashtable;
public class Java11_Collection_Map_2 {
public static void main(String[] args) throws Exception {
// TODO 集合 - Map
// Hashtable
Hashtable table = new Hashtable();
table.put(null, null);
HashMap map = new HashMap();
map.put(null, null);
// table.put()
// table.get()
// table.remove()
// TODO 1. 实现方式不一样的 : 继承父类不一样
// TODO 2. 底层结构的容量不同: HashMap(16), Hashtable(11)
// TODO 3. HashMap的K,V都可以为null, Hashtable的K, V不能是null
// TODO 4. HashMap的数据定位采用的是Hash算法,但是Hashtable采用的就是hashcode
// TODO 5. HashMap的性能较高,但是Hashtable较低
}
}
迭代器:
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
public class Java11_Collection_Map_3 {
public static void main(String[] args) throws Exception {
// TODO 集合 - Map
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
Set<String> keys = map.keySet();
// 因为删了但set没变就会导致数据冲突
// for (String key : keys) {
// if ( "c".equals(key) ) {
// map.remove("b");
// }
// System.out.println(map.get(key));
// }
// TODO 迭代器
Iterator<String> iterator = keys.iterator();
// hasNext方法用于判断是否存在下一条数据
while (iterator.hasNext()) {
// 获取下一条数据
String key = iterator.next();
if("b".equals(key)) {
// remove方法只能对当前数据删除
iterator.remove();
}
System.out.println(map.get(key));
}
}
}
工具类:
import java.util.Arrays;
import java.util.List;
public class Java12_Collection_Util {
public static void main(String[] args) throws Exception {
// TODO 集合 - Arrays
int[] is = {3,5,2,1,4};
int[] is1 = {1,2,3,4,5};
int[] is2 = {1,2,3,4,5,6};
System.out.println(Arrays.toString(is));
System.out.println(is);
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
// 排序(默认为升序)
Arrays.sort(is); // 1,2,3,4,5
System.out.println(Arrays.toString(is));
// 二分查找法,排序后的数组
System.out.println(Arrays.binarySearch(is, 5));
// 数组的比较
System.out.println(Arrays.equals(is2, is1));
System.out.println(Arrays.equals(is2, 0, 5, is1, 0, 5));
}
}
可能出现的问题:
import java.util.*;
public class Java13_Collection_Exception {
public static void main(String[] args) throws Exception {
// TODO 集合 - Exception
// 容量 :不能小于0
ArrayList list = new ArrayList(10);
list.add("a");
list.add("b");
list.add("c");
// 如果访问的集合是数组,那么索引范围就是0 到数组长度-1
// 如果访问的集合是List,那么索引范围就是0 到数据长度-1
// System.out.println(list.get(3));
// NoSuchElementException
// LinkedList list1 = new LinkedList();
// list1.add("a");
// System.out.println(list1.getFirst());
// HashMap一旦循环遍历时,那么如果修改数据,就会发生错误
HashMap map = new HashMap();
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
for (Object o : map.keySet()) {
if ( "b".equals(o) ) {
map.put("d", "4");
}
System.out.println(map.get(o));
}
}
}
异常汇总:
-
java.lang.IllegalArgumentException:设定集合容量时,如果参数为负数,就会发生错误
-
java.util.NoSuchElementException: 从链表结构中获取数据,如果没有数据的场合,那么会发生异常
-
java.lang.IndexOutOfBoundsException:从集合中获取数据,索引不是按照底层的数据结构设定,而是按照数据的个数决定
-
java.util.ConcurrentModificationException:对Map集合进行操作过程中,对数据进行了修改,就会发生错误。
import java.util.*;
public class Java12_Collection_Map_3 {
public static void main(String[] args) throws Exception {
// TODO 集合 - 问题
// 1. java.lang.IllegalArgumentException
// 设定集合容量时,如果参数为负数,就会发生错误
//ArrayList list = new ArrayList(-1);
// 2. java.util.NoSuchElementException
// 从链表结构中获取数据,如果没有数据的场合,那么会发生异常
//LinkedList list = new LinkedList();
//System.out.println(list.getFirst());
// 3. java.lang.IndexOutOfBoundsException
// 从集合中获取数据,索引不是按照底层的数据结构设定,而是按照数据的个数决定
// ArrayList list = new ArrayList();
// list.add("zhangsan");
// list.get(3);
// 4 java.util.ConcurrentModificationException
// 对Map集合进行操作过程中,对数据进行了修改,就会发生错误。
HashMap map = new HashMap();
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
Set set = map.keySet();
for ( Object key : set ) {
if ( "b".equals(key) ) {
map.remove(key);
}
System.out.println(map.get(key));
}
}
}
3.2 IO流
Java: 数据 + 流(转)操作
数据从哪里来,到哪里去
I : Input, 输入(In)
O : Output 输出(Out)
Stream : 流转
文件流:
import java.io.File;
public class Java02_IO_File {
public static void main(String[] args) throws Exception{
// TODO Java IO - 文件流
// TODO File : 文件类型(文件,文件夹),属于java.io
// 创建文件对象, 使用文件路径关联系统文件
String filePath = "F:\\0大学学习\\大三\\大三下\\java7天极速版\\word.txt";
File file = new File(filePath);
System.out.println(file);
// 文件对象的操作
// // TODO 判断当前文件对象是否为文件
// System.out.println(file.isFile());
// // TODO 判断当前文件对象是否为文件夹
// System.out.println(file.isDirectory());
// // TODO 判断文件对象是否存在关联
// System.out.println(file.exists());
if ( file.exists() ) {
// TODO 文件对象存在的情况
System.out.println("文件对象存在");
if (file.isFile()) {
System.out.println("文件对象关联的是一个文件");
System.out.println(file.getName());
System.out.println(file.length());
System.out.println(file.lastModified());
System.out.println(file.getAbsolutePath());
} else if ( file.isDirectory() ) {
System.out.println("文件对象关联的是一个文件夹");
System.out.println(file.getName());
System.out.println(file.lastModified());
System.out.println(file.getAbsolutePath());
String[] list = file.list();
System.out.println("文件夹中的文件:");
for (String s : list) {
System.out.println(s);
}
System.out.println("文件夹中的文件对象:");
File[] files = file.listFiles();
for (File s : files) {
System.out.println(s);
}
}
} else {
// TODO 文件对象不存在的情况
System.out.println("文件对象不存在,没有关联成功");
// TODO 创建多级文件目录
//file.mkdirs();
// TODO 创建新文件
//file.createNewFile();
}
}
}
文件复制:
import java.io.*;
public class Java03_IO_File_Copy {
public static void main(String[] args){
// TODO Java IO - 文件复制
// TODO 数据源文件对象
File srcFile = new File("F:\\0大学学习\\大三\\大三下\\java7天极速版\\word.txt");
// TODO 数据目的地文件对象(自动生成)
File destFilt = new File("F:\\0大学学习\\大三\\大三下\\java7天极速版\\word.txt.copy");
// TODO 文件输入流(管道对象)
FileInputStream in = null;
// TODO 文件输出流(管道对象)
FileOutputStream out = null;
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFilt);
// TODO 打开阀门,流转数据(输入)
//阀门打开一次关闭一次
// int data = in.read();
int data = -1;
// TODO 打开阀门,流转数据(输出)
//out.write(data);
// TODO 问题1 : 代码重复性比较强
// TODO 问题2 : 多读数据
// data = in.read();
// out.write(data);
//
// data = in.read();
// out.write(data);
//
// data = in.read();
// out.write(data);
//
// data = in.read();
// out.write(data);
//
// // TODO 如果文件数据已经全部读取完毕后,那么再去读取数据,读取的结果就是-1,表示无效(结尾)
// data = in.read();
// if ( data != -1 ) {
// out.write(data);
// }
// //System.out.println(data);
while ( (data = in.read()) != -1 ) {
out.write(data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( in != null ) {
try {
//关闭管道
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if ( out != null ) {
try {
//关闭管道
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
缓冲流:
import java.io.*;
public class Java04_IO_File_Copy_Buffer {
public static void main(String[] args){
// TODO Java IO - 文件复制 - 缓冲
// TODO 数据源文件对象
File srcFile = new File("D:\\idea2022\\java-top-speed\\data\\word.txt");
// TODO 数据目的地文件对象(自动生成)
File destFilt = new File("D:\\idea2022\\java-top-speed\\data\\word.txt.copy");
// TODO 文件输入流(管道对象)
FileInputStream in = null;
// TODO 文件输出流(管道对象)
FileOutputStream out = null;
// TODO 缓冲输入流(管道对象)
BufferedInputStream buffIn = null;
// TODO 缓冲输出流(管道对象)
BufferedOutputStream buffOut = null;
// TODO 缓冲区(水桶)
byte[] cache = new byte[1024];
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFilt);
buffIn = new BufferedInputStream(in);
buffOut = new BufferedOutputStream(out);
// TODO 打开阀门,流转数据(输入)
//
int data = -1;
while ( (data = buffIn.read(cache)) != -1 ) {
//0表示从头开始读 data表示读完
buffOut.write(cache, 0, data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( buffIn != null ) {
try {
buffIn.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if ( buffOut != null ) {
try {
buffOut.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
字符流:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Java05_IO_File_Copy_String {
public static void main(String[] args){
// TODO Java IO - 文件复制 - 字符串
// TODO 数据源文件对象
File srcFile = new File("D:\\idea2022\\java-top-speed\\data\\word.txt");
// TODO 数据目的地文件对象(自动生成)
File destFilt = new File("D:\\idea2022\\java-top-speed\\data\\word.txt.copy");
// TODO 文件输入流(管道对象)
FileInputStream in = null;
// TODO 文件输出流(管道对象)
FileOutputStream out = null;
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFilt);
// TODO 打开阀门,流转数据(输入)
//
int data = -1;
StringBuilder ss = new StringBuilder();
while ( (data = in.read()) != -1 ) {
//System.out.println(data + 1);
//out.write(data + 1);
ss.append((char)data);
}
ss.append(" zhangsan");
System.out.println(ss);
// 可以讲字符串转换成字节数组,再讲数组中的每一个字节写入到文件中
// Unicode编码
// byte => -128 ~ 127
// asc => 0 ~ 127
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( in != null ) {
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if ( out != null ) {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
import java.io.*;
public class Java06_IO_File_Copy_String_1 {
public static void main(String[] args){
// TODO Java IO - 文件复制 - 字符串
// TODO 数据源文件对象
File srcFile = new File("D:\\idea2022\\java-top-speed\\data\\word.txt");
// TODO 数据目的地文件对象(自动生成)
File destFilt = new File("D:\\idea2022\\java-top-speed\\data\\word.txt.copy");
// TODO 字符输入流(管道对象)
BufferedReader reader = null;
// TODO 字符输出流(管道对象)
PrintWriter writer = null;
try {
reader = new BufferedReader(new FileReader(srcFile));
writer = new PrintWriter(destFilt);
// TODO 打开阀门,流转数据(输入)
// 读取文件中的一行数据(字符串)
String line = null;
while ( (line = reader.readLine()) != null ) {
System.out.println(line);
writer.println(line);
}
// 刷写数据
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( reader != null ) {
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if ( writer != null ) {
writer.close();
}
}
}
}
序列化:
import java.io.*;
public class Java07_IO_Object {
public static void main(String[] args){
// TODO Java IO - 文件复制 - 序列化 & 反序列化
// TODO 数据文件对象
File dataFile = new File("D:\\idea2022\\java-top-speed\\data\\obj.dat");
// TODO 对象输出流(管道对象)
ObjectOutputStream objectOut = null;
FileOutputStream out = null;
// TODO 对象输入流
ObjectInputStream objectIn = null;
FileInputStream in = null;
try {
// out = new FileOutputStream(dataFile);
// objectOut = new ObjectOutputStream(out);
// Java中只有增加了特殊的标记的类,才能再写文件中时进行序列化操作
// 这里的标记其实就是一个接口
// User user = new User();
// objectOut.writeObject(user);
// objectOut.flush();
// TODO 从文件中读取数据转换成对象
in = new FileInputStream(dataFile);
objectIn = new ObjectInputStream(in);
Object o = objectIn.readObject();
System.out.println(o);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if ( objectOut != null ) {
try {
objectOut.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
class User implements Serializable{
}
常见异常:
FileNotFoundException, IOException
ClassNotFoundException, NotSerializableException
3.3 线程
进程:
1.自己写的程序就是一个进程
2.进程的名字就是执行的类的名字
线程:
Thread是线程类
currentThread 方法用于获取当前正在运行得线程
getName 方法用于获取线程得名称
main方法运行在main线程中
public class Java01_Thread {
public static void main(String[] args) {
// TODO 线程
// Thread是线程类。
// currentThread 方法用于获取当前正在运行得线程
// getName 方法用于获取线程得名称
// TODO 创建线程
//Thread t = new Thread();
MyThread t = new MyThread();
// TODO 启动线程
t.start();
t.stop();
// main方法运行在main线程中
System.out.println(Thread.currentThread().getName());
}
}
// TODO 声明自定义线程类
class MyThread extends Thread {
// 重写运行指令
@Override
public void run() {
System.out.println("MyThread : " + Thread.currentThread().getName());
}
}
线程的状态
串行执行:多个线程连接成串,然后按照顺序执行
并发执行:多个线程是独立,谁抢到了CPU得执行权,谁就能执行
public class Java02_Thread {
public static void main(String[] args) throws Exception {
// TODO 线程 - 执行方式(串行,并发)
// 串行执行:多个线程连接成串,然后按照顺序执行
// 并发执行:多个线程是独立,谁抢到了CPU得执行权,谁就能执行
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.start();
t2.start();
// 将线程连接成串
t1.join();
t2.join();
System.out.println("main线程执行完毕");
}
}
// TODO 第一个线程
class MyThread1 extends Thread {
// 重写运行指令
@Override
public void run() {
System.out.println("MyThread-1 : " + Thread.currentThread().getName());
}
}
// TODO 第二个线程
class MyThread2 extends Thread {
// 重写运行指令
@Override
public void run() {
System.out.println("MyThread-2 : " + Thread.currentThread().getName());
}
}
**线程休眠:**Thread.sleep
线程的工作:
public class Java04_Thread_Run {
public static void main(String[] args) throws Exception {
// TODO 线程 - 运行
// MyThread3 t3 = new MyThread3();
// t3.start();
//
// MyThread4 t4 = new MyThread4();
// t4.start();
// MyThread5 t5 = new MyThread5("t5");
// MyThread5 t55 = new MyThread5("t55");
//
// t5.start();
// t55.start();
// TODO 构建线程对象时,可以只把逻辑传递给这个对象
// 传递逻辑时,需要遵循规则:() -> { 逻辑 }
// Thread t6 = new Thread(() -> {
// System.out.println("线程执行1");
// });
//
// t6.start();
//
// Thread t7 = new Thread(() -> {
// System.out.println("线程执行2");
// });
//
// t7.start();
// TODO 构建线程对象时,可以传递实现了Runnable接口得类得对象,一般使用匿名类
Thread t8 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行");
}
});
t8.start();
System.out.println("main线程执行");
}
}
// TODo 自定义线程
// 1. 继承线程类(父类)
// 2. 重写run方法
class MyThread3 extends Thread {
@Override
public void run() {
System.out.println("t3 线程执行");
}
}
class MyThread4 extends Thread {
@Override
public void run() {
System.out.println("t4 线程执行");
}
}
class MyThread5 extends Thread {
private String threadName;
public MyThread5( String name ) {
threadName = name;
}
@Override
public void run() {
System.out.println(threadName + " 线程执行");
}
}
线程池:
所谓得线程池,其实就是线程对象得容器
可以根据需要,在启动时,创建一个或者多个线程对象
Java种有4种比较常见得线程池
- 创建固定数量得线程对象
ExecutorService是线程服务对象
ExecutorService executorService = Executors.newFixedThreadPool(3); - 根据需求动态创建线程
ExecutorService executorService = Executors.newCachedThreadPool(); - 单一线程
ExecutorService executorService = Executors.newSingleThreadExecutor(); - 定时调度线程
ExecutorService executorService = Executors.newScheduledThreadPool(3);
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Java05_Thread_Pool {
public static void main(String[] args) throws Exception {
// TODO 线程 - 线程池
// 所谓得线程池,其实就是线程对象得容器
// 可以根据需要,在启动时,创建一个或者多个线程对象
// Java种有4种比较常见得线程池
// 1. 创建固定数量得线程对象
// ExecutorService是线程服务对象
//ExecutorService executorService = Executors.newFixedThreadPool(3);
// 2. 根据需求动态创建线程
//ExecutorService executorService = Executors.newCachedThreadPool();
// 3. 单一线程
//ExecutorService executorService = Executors.newSingleThreadExecutor();
// 4. 定时调度线程
ExecutorService executorService = Executors.newScheduledThreadPool(3);
for ( int i = 0; i < 5; i++ ) {
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
}
}
同步和异步:
synchronized - 同步关键字
多个线程访问同步方法时,只能一个一个访问,同步操作
import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Java06_Thread_Syn {
public static void main(String[] args) throws Exception {
// TODO 线程 - 同步
// synchronized - 同步关键字
// 多个线程访问同步方法时,只能一个一个访问,同步操作
// new Hashtable<>(); //同步
//HashMap 异步
// synchronized关键字还可以修饰代码块,称之为同步代码块
/*
synchronized( 用于同步得对象 ) {
处理逻辑
}
*/
Num num = new Num();
User user = new User(num);
user.start();
Bank bank = new Bank(num);
bank.start();
}
}
class Num {
}
class Bank extends Thread {
private Num num;
public Bank( Num num ) {
this.num = num;
}
@Override
public void run() {
synchronized (num) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("9:00, 开发,开始叫号");
num.notifyAll();
}
}
}
class User extends Thread {
// public synchronized void test() {
//
// }
private Num num;
public User( Num num ) {
this.num = num;
}
@Override
public void run() {
synchronized ( num ) {
System.out.println("我是号码1,银行还没开门,我需要等一会");
try {
num.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("叫到我得号了,该我办业务了。");
}
}
}
阻塞:
wait & sleep
- 名字
wait : 等待
sleep : 休眠
从属关系:
wait : Object, 成员方法
sleep : Thread, 静态方法 - 使用方式
wait : 只能使用在同步代码中
sleep : 可以在任意地方法使用 - 阻塞时间
wait : 超时时间(会发生错误)
sleep : 休眠时间(不会发生错误) - 同步处理
wait : 如果执行wait方法,那么其他线程有机会执行当前的同步操作。
sleep : 如果执行sleep方法,那么其他线程没有机会执行当前的同步操作。
线程安全问题:
所谓的线程安全问题,其实就是多个线程在并发执行时,修改了共享内存中共享对象的属性,导致的数据冲突问题
public class Java07_Thread_Safe {
public static void main(String[] args) throws Exception {
// TODO 线程安全
// 所谓的线程安全问题,其实就是多个线程在并发执行时,修改了共享内存中共享对象的属性,导致的数据冲突问题
User7 user = new User7();
Thread t1 = new Thread(()->{
user.name = "zhangsan";
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(user.name);
});
Thread t2 = new Thread(()->{
user.name = "lisi";
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(user.name);
});
t1.start();
t2.start();
System.out.println("main线程执行完毕");
}
}
class User7 {
public String name;
}
3.4 反射
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Java01_Reflect {
public static void main(String[] args) throws Exception {
// TODO 反射
// 多态
User user = new Child();
user.test1();
//user.test2();
// 类对象
Class<? extends User> aClass = user.getClass();
// TODO 获取类的名称
System.out.println(aClass.getName()); // 获取类的完整名称(包含包名)
System.out.println(aClass.getSimpleName()); // 获取类的名称
System.out.println(aClass.getPackageName()); // 获取类的包的名称
// TODO 获取类的父类
Class<?> superclass = aClass.getSuperclass();
System.out.println(superclass);
// TODO 获取类的接口
Class<?>[] interfaces = aClass.getInterfaces();
System.out.println(interfaces.length);
// TODO 获取类的属性
Field f = aClass.getField("xxxxx"); // public
Field f1 = aClass.getDeclaredField("xxxxx"); // 所有权限
Field[] fields = aClass.getFields();// public
Field[] declaredFields = aClass.getDeclaredFields(); // 所有权限
// TODO 获取类的方法
Method method = aClass.getMethod("test2");// public
Method xxxx = aClass.getDeclaredMethod("xxxx"); // 所有权限
Method[] methods = aClass.getMethods();// public
Method[] declaredMethods = aClass.getDeclaredMethods(); // 所有权限
// TODO 构造方法
Constructor<? extends User> constructor = aClass.getConstructor();
Constructor<?>[] constructors = aClass.getConstructors();
aClass.getDeclaredConstructor();
// TODO 获取权限(修饰符) :多个修饰符会融合成一个int值
int modifiers = aClass.getModifiers();
boolean aPrivate = Modifier.isPrivate(modifiers);//专门的类判断修饰符
}
}
class User {
public void test1() {
System.out.println("test1...");
}
}
class Child extends User {
public void test2() {
System.out.println("test2...");
}
}
类加载器:
Java种的类主要分为3种:
- Java核心类库种的类:String, Object
- JVM 软件平台开发商
- 自己写的类,User, Child
类加载器也有3种:
- BootClassLoader : 启动类加载器(加载类时,采用操作系统平台语言实现)
- PlatformClassLoader :平台类加载器
- AppClassLoader : 应用类加载器
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Java02_Reflect_ClassLoader {
public static void main(String[] args) throws Exception {
// TODO 反射 - 类加载器
// 加载类
// Java种的类主要分为3种:
// 1. Java核心类库种的类:String, Object
// 2. JVM 软件平台开发商
// 3. 自己写的类,User, Child
// 类加载器也有3种
// 1. BootClassLoader : 启动类加载器(加载类时,采用操作系统平台语言实现)
// 2. PlatformClassLoader :平台类加载器
// 3. AppClassLoader : 应用类加载器
// TODo 获取类的信息
Class<Student> studentClass = Student.class;
// 获取类的加载器对象
ClassLoader classLoader = studentClass.getClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
System.out.println(classLoader.getParent().getParent());
Class<String> stringClass = String.class;
// 获取类的加载器对象
ClassLoader classLoader1 = stringClass.getClassLoader();
System.out.println(classLoader1);
// 加载Java核心类库 > 平台类库 > 自己类
}
}
class Student {
}
练习:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Java03_Reflect_Test {
public static void main(String[] args) throws Exception {
// TODO 反射 - 练习
// 员工的登录功能,
// 构造方法对象
Class empClass = Emp.class;
Constructor declaredConstructor = empClass.getDeclaredConstructor();
// 构建对象
Object emp = declaredConstructor.newInstance();
// 获取对象的属性
Field account = empClass.getField("account");
Field password = empClass.getField("password");
// 给属性赋值
account.set(emp, "admin");
password.set(emp, "admin");
// 获取登录方法
Method login = empClass.getMethod("login");
// 调用方法
Object result = login.invoke(emp);
System.out.println(result);
}
}
// 员工
class Emp {
public String account;
public String password;
public boolean login() {
if ( "admin".equals(account) && "admin".equals(password) ) {
return true;
} else {
return false;
}
}
}
常见异常:
-
ClassNotFoundException, 类找不到异常
-
NoSuchMethodException, 没有方法的异常
-
IllegalArgumentException, 参数异常
-
NoSuchFieldException, 没有顺序的异常
-
IllegalAccessException, 访问权限异常
-
InvocationTargetException, 调用目标异常
hrow new RuntimeException(e);
}
System.out.println(user.name);
});
t1.start();
t2.start();System.out.println("main线程执行完毕");
}
}
class User7 {
public String name;
}
[外链图片转存中...(img-KgHiEsdt-1674281930133)]
### 3.4 反射
```java
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Java01_Reflect {
public static void main(String[] args) throws Exception {
// TODO 反射
// 多态
User user = new Child();
user.test1();
//user.test2();
// 类对象
Class<? extends User> aClass = user.getClass();
// TODO 获取类的名称
System.out.println(aClass.getName()); // 获取类的完整名称(包含包名)
System.out.println(aClass.getSimpleName()); // 获取类的名称
System.out.println(aClass.getPackageName()); // 获取类的包的名称
// TODO 获取类的父类
Class<?> superclass = aClass.getSuperclass();
System.out.println(superclass);
// TODO 获取类的接口
Class<?>[] interfaces = aClass.getInterfaces();
System.out.println(interfaces.length);
// TODO 获取类的属性
Field f = aClass.getField("xxxxx"); // public
Field f1 = aClass.getDeclaredField("xxxxx"); // 所有权限
Field[] fields = aClass.getFields();// public
Field[] declaredFields = aClass.getDeclaredFields(); // 所有权限
// TODO 获取类的方法
Method method = aClass.getMethod("test2");// public
Method xxxx = aClass.getDeclaredMethod("xxxx"); // 所有权限
Method[] methods = aClass.getMethods();// public
Method[] declaredMethods = aClass.getDeclaredMethods(); // 所有权限
// TODO 构造方法
Constructor<? extends User> constructor = aClass.getConstructor();
Constructor<?>[] constructors = aClass.getConstructors();
aClass.getDeclaredConstructor();
// TODO 获取权限(修饰符) :多个修饰符会融合成一个int值
int modifiers = aClass.getModifiers();
boolean aPrivate = Modifier.isPrivate(modifiers);//专门的类判断修饰符
}
}
class User {
public void test1() {
System.out.println("test1...");
}
}
class Child extends User {
public void test2() {
System.out.println("test2...");
}
}
类加载器:
Java种的类主要分为3种:
- Java核心类库种的类:String, Object
- JVM 软件平台开发商
- 自己写的类,User, Child
类加载器也有3种:
- BootClassLoader : 启动类加载器(加载类时,采用操作系统平台语言实现)
- PlatformClassLoader :平台类加载器
- AppClassLoader : 应用类加载器
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Java02_Reflect_ClassLoader {
public static void main(String[] args) throws Exception {
// TODO 反射 - 类加载器
// 加载类
// Java种的类主要分为3种:
// 1. Java核心类库种的类:String, Object
// 2. JVM 软件平台开发商
// 3. 自己写的类,User, Child
// 类加载器也有3种
// 1. BootClassLoader : 启动类加载器(加载类时,采用操作系统平台语言实现)
// 2. PlatformClassLoader :平台类加载器
// 3. AppClassLoader : 应用类加载器
// TODo 获取类的信息
Class<Student> studentClass = Student.class;
// 获取类的加载器对象
ClassLoader classLoader = studentClass.getClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
System.out.println(classLoader.getParent().getParent());
Class<String> stringClass = String.class;
// 获取类的加载器对象
ClassLoader classLoader1 = stringClass.getClassLoader();
System.out.println(classLoader1);
// 加载Java核心类库 > 平台类库 > 自己类
}
}
class Student {
}
练习:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Java03_Reflect_Test {
public static void main(String[] args) throws Exception {
// TODO 反射 - 练习
// 员工的登录功能,
// 构造方法对象
Class empClass = Emp.class;
Constructor declaredConstructor = empClass.getDeclaredConstructor();
// 构建对象
Object emp = declaredConstructor.newInstance();
// 获取对象的属性
Field account = empClass.getField("account");
Field password = empClass.getField("password");
// 给属性赋值
account.set(emp, "admin");
password.set(emp, "admin");
// 获取登录方法
Method login = empClass.getMethod("login");
// 调用方法
Object result = login.invoke(emp);
System.out.println(result);
}
}
// 员工
class Emp {
public String account;
public String password;
public boolean login() {
if ( "admin".equals(account) && "admin".equals(password) ) {
return true;
} else {
return false;
}
}
}
常见异常:
- ClassNotFoundException, 类找不到异常
- NoSuchMethodException, 没有方法的异常
- IllegalArgumentException, 参数异常
- NoSuchFieldException, 没有顺序的异常
- IllegalAccessException, 访问权限异常
- InvocationTargetException, 调用目标异常