视频地址: https://www.bilibili.com/video/BV1Cv411372m
此笔记是 P1 - P85
1. 开始
1.1 注释(理解)
注释是对代码的解释和说明文字,可以提高程序的可读性,因此在程序中添加必要的注释文字十分重要。Java中的注释分为三种:
单行注释。单行注释的格式是使用//,从//开始至本行结尾的文字将作为注释文字。
// 这是单行注释文字
多行注释。多行注释的格式是使用/* 和 */将一段较长的注释括起来。
/*
这是多行注释文字
这是多行注释文字
这是多行注释文字
*/
注意:多行注释不能嵌套使用。
文档注释。文档注释以/**
开始,以*/
结束。(以后讲)
1.2 字面量(应用)
作用:告诉程序员,数据在程序中的书写格式。
字面量类型 | 说明 | 程序中的写法 |
---|---|---|
整数 | 不带小数的数字 | 666,-88 |
小数 | 带小数的数字 | 13.14,-5.21 |
字符 | 必须使用单引号,有且仅能一个字符 | ‘A’,‘0’, ‘我’ |
字符串 | 必须使用双引号,内容可有可无 | “HelloWorld”,“黑马程序员” |
布尔值 | 布尔值,表示真假,只有两个值:true,false | true 、false |
空值 | 一个特殊的值,空值 | 值是:null |
public class Demo {
public static void main(String[] args) {
System.out.println(10); // 输出一个整数
System.out.println(5.5); // 输出一个小数
System.out.println('a'); // 输出一个字符
System.out.println(true); // 输出boolean值true
System.out.println("欢迎来到黑马程序员"); // 输出字符串
}
}
println:表示换行
\n:表示换行
\t:表示空格
1.3 数据类型(记忆、应用)
1.3.1 计算机存储单元
计算机底层都是一些数字电路(理解成开关),用开表示0、关表示1,这些01的形式就是二进制。
数据在计算机底层都是采用二进制存储的,在计算机中认为一个开关表示的0|1称为1位(b),每8位称为一个字节(B), 所以1B=8b
字节是计算机中数据的最小单位。
我们知道计算机是可以用来存储数据的,但是无论是内存还是硬盘,计算机存储设备的最小信息单元叫“位(bit)”,我们又称之为“比特位”,通常用小写的字母”b”表示。而计算机中最基本的存储单元叫“字节(byte)”,
通常用大写字母”B”表示,字节是由连续的8个位组成。
除了字节外还有一些常用的存储单位,其换算单位如下:
1B(字节) = 8bit
1KB = 1024B
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1.3.2 Java中的数据类型
Java是一个强类型语言,Java中的数据必须明确数据类型。在Java中的数据类型包括基本数据类型和引用数据类型两种。
Java中的基本数据类型:
数据类型 | 关键字 | 内存占用 | 取值范围 |
---|---|---|---|
整数 | byte | 1 | 负的2的7次方 ~ 2的7次方-1(-128~127) |
short | 2 | 负的2的15次方 ~ 2的15次方-1(-32768~32767) | |
int(默认) | 4 | 负的2的31次方 ~ 2的31次方-1 | |
long | 8 | 负的2的63次方 ~ 2的63次方-1 | |
浮点数 | float | 4 | 1.401298e-45 ~ 3.402823e+38 |
double(默认) | 8 | 4.9000000e-324 ~ 1.797693e+308 | |
字符 | char | 2 | 0-65535 |
布尔 | boolean | 1 | true,false |
说明:
e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方。
在java中整数默认是int类型,浮点数默认是double类型。
1.3.3 引用数据类型
1.4 变量(应用)
1.4.1 变量的定义
变量:在程序运行过程中,其值可以发生改变的量。
从本质上讲:变量就是用来存储一个数据的内存区域(可以理解成盒子),且里面存储的数据可以变化。
作用:存储一个数据的,可以改变里面的存储的数据。
变量的定义格式:
数据类型 变量名 = 初始化值; // 声明变量并赋值
int age = 18;
System.out.println(age);
或者
// 先声明,后赋值(使用前赋值即可)
数据类型 变量名;
变量名 = 初始化值;
double money;
money = 55.5;
System.out.println(money);
还可以在同一行定义多个同一种数据类型的变量,中间使用逗号隔开。但不建议使用这种方式,降低程序的可读性。
int a = 10, b = 20; // 定义int类型的变量a和b,中间使用逗号隔开
System.out.println(a);
System.out.println(b);
int c,d; // 声明int类型的变量c和d,中间使用逗号隔开
c = 30;
d = 40;
System.out.println(c);
System.out.println(d);
变量的使用:通过变量名访问即可。
1.4.2 变量的分类
- 局部变量
- 成员变量
- 静态成员变量
- 实例成员变量
1.4.3 使用变量时的注意事项
-
在同一对花括号中,变量名不能重复。
-
变量定义是可以只初始化不赋值,但变量在使用之前,必须赋值。
-
定义long类型的变量时,需要在整数的后面加L(大小写均可,建议大写)。因为整数默认是int类型,整数太大可能超出int范围。
-
定义float类型的变量时,需要在小数的后面加F(大小写均可,建议大写)。因为浮点数的默认类型是double, double的取值范围是大于float的,类型不兼容。
-
什么类型的变量,一定是存放什么类型的数据。
1.5 关键字、标志符(记忆、理解)
关键字
Java自己保留的一些单词,作为特殊功能的,例如:public、class、byte、short、int、long、double…
我们不能用来作为类名或者是变量名称,否则报错。
注意:关键字很多,不用刻意去记。
abstract | assert | boolean | break | byte |
---|---|---|---|---|
case | catch | char | class | const |
continue | default | do | double | else |
enum | extends | final | finally | float |
for | goto | if | implements | import |
instanceof | int | interface | long | native |
new | package | private | protected | public |
return | strictfp | short | static | super |
switch | synchronized | this | throw | throws |
transient | try | void | volatile | while |
标志符
标志符就是由一些字符、符号组合起来的名称,用于给类,方法,变量等起名字的规矩。
基本要求:由数字、字母、下划线(_)和美元符($)等组成
强制要求:不能以数字开头、不能是关键字、区分大小写
基本命令规范
变量名称:满足标识符规则,建议全英文、有意义、首字母小写,满足“驼峰模式”,例如:int studyNumber = 59。
类名称: 满足标识符规则,建议全英文、有意义、首字母大写,满足“驼峰模式”,例如:HelloWorld.java。
2.类型转换问题
2.1类型转换(理解)
在Java中,会存在不同类型的数据需要一起参与运算,所以这些数据类型之间是需要相互转换的,分为两种情况:自动类型转换和强制类型转换。
2.2自动类型转换
类型范围小的变量,可以直接赋值给类型范围大*的变量。
把一个表示数据范围小的数值或者变量赋值给另一个表示数据范围大的变量。这种转换方式是自动的,直接书写即可。例如:
double num = 10; // 将int类型的10直接赋值给double类型
System.out.println(num); // 输出10.0
byte a = 12 ;
int b = a;
System.out.println(b); // 12
char ch = 'a'; //00000000 01100001
int code = ch; //00000000 00000000 00000000 01100001
System.out.println(code); // 97
总结:
2.3表达式的自动类型转换
在表达式中,小范围类型的变量会自动转换成当前较大范围的类型再运算。
注意事项:
表达式的最终结果类型由表达式中的最高类型决定。
在表达式中,byte、short、char 是直接转换成int类型参与运算的。
总结:
2.4强制类型转换
类型范围大的数据或者变量,不能直接赋值给类型范围小的变量,会报错,把一个表示数据范围大的数值或者变量赋值给另一个表示数据范围小的变量必须进行强制类型转换。
强制类型转换在idea中的快捷键是:alt+enter ——>选第一个
强制类型转换格式:目标数据类型 变量名 = (目标数据类型)值或者变量;
例如:
double num1 = 5.5;
int num2 = (int) num1; // 将double类型的num1强制转换为int类型
System.out.println(num2); // 输出5(小数位直接舍弃)
说明:
- char类型的数据转换为int类型是按照码表中对应的int值进行计算的。比如在ASCII码表中,'a’对应97。
int a = 'a';
System.out.println(a); // 将输出97
- 整数默认是int类型,byte、short和char类型数据参与运算均会自动转换为int类型。
byte b1 = 10;
byte b2 = 20;
byte b3 = b1 + b2;
// 第三行代码会报错,b1和b2会自动转换为int类型,计算结果为int,int赋值给byte需要强制类型转换。
// 修改为:
int num = b1 + b2;
// 或者:
byte b3 = (byte) (b1 + b2);
【注】boolean类型不能与其他基本数据类型相互转换。
总结:
3. 运算符
3.1 算术运算符(理解)
3.1.1 运算符和表达式
运算符:对常量或者变量进行操作的符号
表达式:用运算符把常量或者变量连接起来符合java语法的式子就可以称为表达式。
不同运算符连接的表达式体现的是不同类型的表达式。
举例说明:
int a = 10;
int b = 20;
int c = a + b;
+:是运算符,并且是算术运算符。
a + b:是表达式,由于+是算术运算符,所以这个表达式叫算术表达式。
3.1.2 算术运算符
符号 | 作用 | 说明 |
---|---|---|
+ | 加 | 参看小学一年级 |
- | 减 | 参看小学一年级 |
* | 乘 | 参看小学二年级,与“×”相同 |
/ | 除 | 参看小学二年级,与“÷”相同 |
% | 取余 | 获取的是两个数据做除法的余数 |
注意:
/和%的区别:两个数据做除法,/取结果的商,%取结果的余数。
整数操作只能得到整数,要想得到小数,必须有浮点数参与运算。
int a = 10;
int b = 3;
System.out.println(a / b); // 输出结果3
System.out.println(a % b); // 输出结果1
数据拆分案例:
3.1.3 加符号做连接符
总结:
char类型参与算术运算,使用的是计算机底层对应的十进制数值。需要我们记住三个字符对应的数值:
‘a’ – 97 a-z是连续的,所以’b’对应的数值是98,'c’是99,依次递加
‘A’ – 65 A-Z是连续的,所以’B’对应的数值是66,'C’是67,依次递加
‘0’ – 48 0-9是连续的,所以’1’对应的数值是49,'2’是50,依次递加
// 可以通过使用字符与整数做算术运算,得出字符对应的数值是多少
char ch1 = 'a';
System.out.println(ch1 + 1); // 输出98,97 + 1 = 98
char ch2 = 'A';
System.out.println(ch2 + 1); // 输出66,65 + 1 = 66
char ch3 = '0';
System.out.println(ch3 + 1); // 输出49,48 + 1 = 49
当“+”操作中出现字符串时,这个”+”是字符串连接符,而不是算术运算。
System.out.println("itheima"+ 666); // 输出:itheima666
在”+”操作中,如果出现了字符串,就是连接运算符,否则就是算术运算。当连续进行“+”操作时,从左到右逐个执行。
System.out.println(1 + 99 + "年黑马"); // 输出:199年黑马
System.out.println(1 + 2 + "itheima" + 3 + 4); // 输出:3itheima34
// 可以使用小括号改变运算的优先级
System.out.println(1 + 2 + "itheima" + (3 + 4)); // 输出:3itheima7
3.2 赋值运算符(应用)
赋值运算符的作用是将一个表达式的值赋给左边,左边必须是可修改的,不能是常量。
符号 | 作用 | 说明 |
---|---|---|
= | 赋值 | a=10,将10赋值给变量a |
+= | 加后赋值 | a+=b,将a+b的值给a |
-= | 减后赋值 | a-=b,将a-b的值给a |
*= | 乘后赋值 | a*=b,将a×b的值给a |
/= | 除后赋值 | a/=b,将a÷b的商给a |
%= | 取余后赋值 | a%=b,将a÷b的余数给a |
注意:
扩展的赋值运算符隐含了强制类型转换。
short s = 10;
s = s + 10; // 此行代码报错,因为运算中s提升为int类型,运算结果int赋值给short可能损失精度
//修改:s = (short) (s + 10); 这样才能赋值给s
s += 10; // 此行代码没有问题,隐含了强制类型转换,相当于 s = (short) (s + 10);
3.3 自增自减运算符(理解)
符号 | 作用 | 说明 |
---|---|---|
++ | 自增 | 变量的值加1 |
– | 自减 | 变量的值减1 |
注意事项:
++和-- 既可以放在变量的后边,也可以放在变量的前边。
单独使用的时候, ++和-- 无论是放在变量的前边还是后边,结果是一样的。
参与操作的时候,如果放在变量的后边,先拿变量参与操作,后拿变量做++或者–。
参与操作的时候,如果放在变量的前边,先拿变量做++或者–,后拿变量参与操作。
最常见的用法:单独使用。
int i = 10;
i++; // 单独使用
System.out.println("i:" + i); // i:11
int j = 10;
++j; // 单独使用
System.out.println("j:" + j); // j:11
int x = 10;
int y = x++; // 赋值运算,++在后边,所以是使用x原来的值赋值给y,x本身自增1
System.out.println("x:" + x + ", y:" + y); // x:11,y:10
int m = 10;
int n = ++m; // 赋值运算,++在前边,所以是使用m自增后的值赋值给n,m本身自增1
System.out.println("m:" + m + ", m:" + m); // m:11,m:11
练习:
int x = 10;
int y = x++ + x++ + x++;
System.out.println(y); // y的值是多少?
/*
解析,三个表达式都是++在后,所以每次使用的都是自增前的值,但程序自左至右执行,所以第一次自增时,使用的是10进行计算,但第二次自增时,x的值已经自增到11了,所以第二次使用的是11,然后再次自增。。。
所以整个式子应该是:int y = 10 + 11 + 12;
输出结果为33。
*/
注意:通过此练习深刻理解自增和自减的规律,但实际开发中强烈建议不要写这样的代码!小心挨打!
3.4 关系运算符(应用)
关系运算符有6种关系,分别为小于、小于等于、大于、等于、大于等于、不等于。
符号 | 说明 |
---|---|
== | a==b,判断a和b的值是否相等,成立为true,不成立为false |
!= | a!=b,判断a和b的值是否不相等,成立为true,不成立为false |
> | a>b,判断a是否大于b,成立为true,不成立为false |
>= | a>=b,判断a是否大于等于b,成立为true,不成立为false |
< | a<b,判断a是否小于b,成立为true,不成立为false |
<= | a<=b,判断a是否小于等于b,成立为true,不成立为false |
注意事项:
关系运算符的结果都是boolean类型,要么是true,要么是false。
千万不要把“”误写成“=”,"“是判断是否相等的关系,”="是赋值。
int a = 10;
int b = 20;
System.out.println(a == b); // false
System.out.println(a != b); // true
System.out.println(a > b); // false
System.out.println(a >= b); // false
System.out.println(a < b); // true
System.out.println(a <= b); // true
System.out.println(a = b); // 20
// 关系运算的结果肯定是boolean类型,所以也可以将运算结果赋值给boolean类型的变量
boolean flag = a > b;
System.out.println(flag); // 输出false
3.5 逻辑运算符(应用)
逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断的结果是 true 或 false。
符号 | 作用 | 说明 |
---|---|---|
& | 逻辑与 | a&b,a和b都是true,结果为true。只要一个为false,结果一定是false |
| | 逻辑或 | a|b,a和b都是false,结果为false。只要一个为true,结果一定是true |
^ | 逻辑异或 | a^b,a和b结果不同为true,相同为false |
! | 逻辑非 | !a,结果和a的结果正好相反 |
//定义变量
int i = 10;
int j = 20;
int k = 30;
//& “与”,并且的关系,只要表达式中有一个值为false,结果即为false
System.out.println((i > j) & (i > k)); //false & false,输出false
System.out.println((i < j) & (i > k)); //true & false,输出false
System.out.println((i > j) & (i < k)); //false & true,输出false
System.out.println((i < j) & (i < k)); //true & true,输出true
System.out.println("--------");
//| “或”,或者的关系,只要表达式中有一个值为true,结果即为true
System.out.println((i > j) | (i > k)); //false | false,输出false
System.out.println((i < j) | (i > k)); //true | false,输出true
System.out.println((i > j) | (i < k)); //false | true,输出true
System.out.println((i < j) | (i < k)); //true | true,输出true
System.out.println("--------");
//^ “异或”,相同为false,不同为true
System.out.println((i > j) ^ (i > k)); //false ^ false,输出false
System.out.println((i < j) ^ (i > k)); //true ^ false,输出true
System.out.println((i > j) ^ (i < k)); //false ^ true,输出true
System.out.println((i < j) ^ (i < k)); //true ^ true,输出false
System.out.println("--------");
//! “非”,取反
System.out.println((i > j)); //false
System.out.println(!(i > j)); //!false,,输出true
3.5.1短路逻辑运算符
符号 | 作用 | 说明 |
---|---|---|
&& | 短路与 | 判断结果与"&"一样。过程是左边为false,右边则不执行。 |
|| | 短路或 | 判断结果与"|"一样。过程是左边为true,右边则不执行。 |
在逻辑与运算中,只要有一个表达式的值为false,那么结果就可以判定为false了,没有必要将所有表达式的值都计算出来,短路与操作就有这样的效果,可以提高效率。同理在逻辑或运算中,一旦发现值为true,右边的表达式将不再参与运算。
-
逻辑与&,无论左边真假,右边都要执行。
-
短路与&&,如果左边为真,右边执行;如果左边为假,右边不执行。
-
逻辑或|,无论左边真假,右边都要执行。
-
短路或||,如果左边为假,右边执行;如果左边为真,右边不执行。
int x = 3;
int y = 4;
System.out.println((x++ > 4) & (y++ > 5)); // 两个表达都会运算
System.out.println(x); // 4
System.out.println(y); // 5
System.out.println((x++ > 4) && (y++ > 5)); // 左边已经可以确定结果为false,右边不参与运算
System.out.println(x); // 4
System.out.println(y); // 4
【注】
- 开发中用 &&、||、! 比较多
- 既想看结果又想让前后两部分都执行,用 &、|
3.6 三元运算符(理解)
三元运算符语法格式:
关系表达式 ? 表达式1 : 表达式2;
解释:问号前面的位置是判断的条件,判断结果为boolean型,为true时调用表达式1,为false时调用表达式2。其逻辑为:如果条件表达式成立或者满足则执行表达式1,否则执行第二个。
举例:
int a = 10;
int b = 20;
int c = a > b ? a : b; // 判断 a>b 是否为真,如果为真取a的值,如果为假,取b的值
三元运算符案例:
1、需求:动物园里有两只老虎,已知两只老虎的体重分别为180kg、200kg,请用程序实现判断两只老虎的体重是否相同。
public class OperatorTest01 {
public static void main(String[] args) {
//1:定义两个变量用于保存老虎的体重,单位为kg,这里仅仅体现数值即可。
int weight1 = 180;
int weight2 = 200;
//2:用三元运算符实现老虎体重的判断,体重相同,返回true,否则,返回false。
boolean b = weight1 == weight2 ? true : false;
//3:输出结果
System.out.println("b:" + b);
}
}
2、需求:一座寺庙里住着三个和尚,已知他们的身高分别为150cm、210cm、165cm,请用程序实现获取这三个和尚的最高身高。
public class OperatorTest02 {
public static void main(String[] args) {
//1:定义三个变量用于保存和尚的身高,单位为cm,这里仅仅体现数值即可。
int height1 = 150;
int height2 = 210;
int height3 = 165;
//2:用三元运算符获取前两个和尚的较高身高值,并用临时身高变量保存起来。
int tempHeight = height1 > height2 ? height1 : height2;
//3:用三元运算符获取临时身高值和第三个和尚身高较高值,并用最大身高变量保存。
int maxHeight = tempHeight > height3 ? tempHeight : height3;
//4:输出结果
System.out.println("maxHeight:" + maxHeight);
}
}
public class OperatorTest02 {
public static void main(String[] args) {
// 三元运算符的拓展
int i = 150;
int j = 210;
int k = 165;
int maxHeight = i > j ? (i > k ? i : k) : (j > k ? j : k);
System.out.println("maxHeight:" + maxHeight);
}
}
3.7 运算符优先级
4. 数据输入/键盘录入(应用)
我们可以通过 Scanner 类来获取用户的输入。使用步骤如下:
1、导包。Scanner 类在java.util包下,所以需要将该类导入。导包的语句需要定义在类的上面。
import java.util.Scanner;
2、创建Scanner对象。【在idea中,写下这行代码,自动导包,不需要第一步的操作了】
Scanner sc = new Scanner(System.in);// 创建Scanner对象,sc表示变量名,其他均不可变
3、接收数据
int i = sc.nextInt(); // 表示将键盘录入的值作为int数返回。
示例:
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
//创建对象
Scanner sc = new Scanner(System.in);
//接收数据
int x = sc.nextInt();
//输出数据
System.out.println("x:" + x);
}
}
改写三个和尚案例,数据使用键盘录入。
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
//身高未知,采用键盘录入实现。首先导包,然后创建对象。
Scanner sc = new Scanner(System.in);
//键盘录入三个身高分别赋值给三个变量。
System.out.println("请输入第一个和尚的身高:");
int height1 = sc.nextInt();
System.out.println("请输入第二个和尚的身高:");
int height2 = sc.nextInt();
System.out.println("请输入第三个和尚的身高:");
int height3 = sc.nextInt();
//用三元运算符获取前两个和尚的较高身高值,并用临时身高变量保存起来。
int tempHeight = height1 > height2 ? height1 : height2;
//用三元运算符获取临时身高值和第三个和尚身高较高值,并用最大身高变量保存。
int maxHeight = tempHeight > height3 ? tempHeight : height3;
//输出结果。
System.out.println("这三个和尚中身高最高的是:" + maxHeight +"cm");
}
}
import java.util.Scanner;
public class IfTest02 {
public static void main(String[] args) {
//小明的考试成绩未知,可以使用键盘录入的方式获取值
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个分数:");
int score = sc.nextInt();
//由于奖励种类较多,属于多种判断,采用if...else...if格式实现
//为每种判断设置对应的条件
//为每种判断设置对应的奖励
//数据测试:正确数据,边界数据,错误数据
if(score>100 || score<0) {
System.out.println("你输入的分数有误");
} else if(score>=95 && score<=100) {
System.out.println("山地自行车一辆");
} else if(score>=90 && score<=94) {
System.out.println("游乐场玩一次");
} else if(score>=80 && score<=89) {
System.out.println("变形金刚玩具一个");
} else {
System.out.println("胖揍一顿");
}
}
}
总结:
5、流程控制语句(应用)
在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。所以,我们必须清楚每条语句的执行流程。而且,很多时候要通过控制语句的执行顺序来实现我们想要的功能。
5.1 流程控制语句分类
顺序结构(程序默认流程)
分支结构(if, switch)
循环结构(for, while, do…while)
5.2 顺序结构
顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。
顺序结构执行流程图:
5.3 分支结构:if语句
5.3.1 if语句格式1
格式:
if (关系表达式) {
语句体;
}
执行流程:
①首先计算关系表达式的值
②如果关系表达式的值为true就执行语句体
③如果关系表达式的值为false就不执行语句体
④继续执行后面的语句内容
示例:
public class IfDemo {
public static void main(String[] args) {
System.out.println("开始");
//定义两个变量
int a = 10;
int b = 20;
//需求:判断a和b的值是否相等,如果相等,就在控制台输出:a等于b
if(a == b) {
System.out.println("a等于b");
}
//需求:判断a和c的值是否相等,如果相等,就在控制台输出:a等于c
int c = 10;
if(a == c) {
System.out.println("a等于c");
}
System.out.println("结束");
}
}
5.3.2 if语句格式2
格式:
if (关系表达式) {
语句体1;
} else {
语句体2;
}
执行流程:
①首先计算关系表达式的值
②如果关系表达式的值为true就执行语句体1
③如果关系表达式的值为false就执行语句体2
④继续执行后面的语句内容
示例:
public class IfDemo02 {
public static void main(String[] args) {
System.out.println("开始");
//定义两个变量
int a = 10;
int b = 20;
b = 5;
//需求:判断a是否大于b,如果是,在控制台输出:a的值大于b,否则,在控制台输出:a的值不大于b
if(a > b) {
System.out.println("a的值大于b");
} else {
System.out.println("a的值不大于b");
}
System.out.println("结束");
}
}
if语句案例:奇偶数
需求:任意给出一个整数,请用程序实现判断该整数是奇数还是偶数,并在控制台输出该整数是奇数还是偶数。
分析:
①为了体现任意给出一个整数,采用键盘录入一个数据
②判断整数是偶数还是奇数要分两种情况进行判断,使用if…else结构
③判断是否偶数需要使用取余运算符实现该功能 number % 2 == 0
④根据判定情况,在控制台输出对应的内容
import java.util.Scanner;
public class IfTest01 {
public static void main(String[] args) {
//为了体现任意给出一个整数,采用键盘录入一个数据。(导包,创建对象,接收数据)
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数:");
int number = sc.nextInt();
//判断整数是偶数还是奇数要分两种情况进行判断,使用if..else结构
//判断是否偶数需要使用取余运算符实现该功能 number % 2 == 0
//根据判定情况,在控制台输出对应的内容
if(number%2 == 0) {
System.out.println(number + "是偶数");
} else {
System.out.println(number + "是奇数");
}
}
}
5.3.3 if语句格式3
格式:
if (关系表达式1) {
语句体1;
} else if (关系表达式2) {
语句体2;
}
…
else {
语句体n+1;
}
执行流程:
①首先计算关系表达式1的值
②如果值为true就执行语句体1;如果值为false就计算关系表达式2的值
③如果值为true就执行语句体2;如果值为false就计算关系表达式3的值
④…
⑤如果没有任何关系表达式为true,就执行语句体n+1。
示例:键盘录入一个星期数(1,2,…7),输出对应的星期一,星期二,…星期日
import java.util.Scanner;
public class IfDemo03 {
public static void main(String[] args) {
System.out.println("开始");
// 需求:键盘录入一个星期数(1,2,...7),输出对应的星期一,星期二,...星期日
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个星期数(1-7):");
int week = sc.nextInt();
if(week == 1) {
System.out.println("星期一");
} else if(week == 2) {
System.out.println("星期二");
} else if(week == 3) {
System.out.println("星期三");
} else if(week == 4) {
System.out.println("星期四");
} else if(week == 5) {
System.out.println("星期五");
} else if(week == 6) {
System.out.println("星期六");
} else {
System.out.println("星期日");
}
System.out.println("结束");
}
}
if语句格式3案例:
需求:小明快要期末考试了,小明爸爸对他说,会根据他不同的考试成绩,送他不同的礼物,假如你可以控制小明的得分,请用程序实现小明到底该获得什么样的礼物,并在控制台输出。
分析:
①小明的考试成绩未知,可以使用键盘录入的方式获取值
②由于奖励种类较多,属于多种判断,采用if…else…if格式实现
③为每种判断设置对应的条件
④为每种判断设置对应的奖励
5.4 分支结构:switch语句
也是匹配条件去执行分支,适合做值匹配的分支选择,结构清晰,格式良好。
5.4.1 switch语句结构(掌握)
-
格式
switch (表达式) { case 值1: 语句体1; break; case 值2: 语句体2; break; ... default: 语句体n+1; break; }
-
执行流程:
- 先执行表达式的值,拿着这个值去与case后的值进行匹配。
- 匹配哪个case的值为true就执行哪个case,遇到break就跳出该case的switch分支。
- 如果case后的值都不匹配则执行default代码。
【注】
5.4.2 switch语句练习-春夏秋冬(应用)
- 典型的switch穿透性的使用!
- 需求:一年有12个月,分属于春夏秋冬4个季节,键盘录入一个月份,请用程序实现判断该月份属于哪个季节,并输出。
- 运行结果:
春:3、4、5
夏:6、7、8
秋:9、10、11
冬:1、2、12
- 示例代码:
public class Demo1 {
public static void main(String[] args) {
//键盘录入月份数据,使用变量接收
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个月份:");
int month = sc.nextInt();
//case穿透
switch(month) {
case 1:
case 2:
case 12:
System.out.println("冬季");
break;
case 3:
case 4:
case 5:
System.out.println("春季");
break;
case 6:
case 7:
case 8:
System.out.println("夏季");
break;
case 9:
case 10:
case 11:
System.out.println("秋季");
break;
default:
System.out.println("你输入的月份有误");
}
}
}
-
注意:如果switch中得case,没有对应break的话,则会出现case穿透的现象。
-
【总结】:
5.5 循环结构:for循环
5.5.1 for循环结构(掌握)
-
循环:
循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体语句,当反复执行这个循环体时,需要在合适的时候把循环判断条件修改为false,从而结束循环,否则循环将一直执行下去,形成死循环。
-
for循环格式:
for (初始化语句;条件判断语句;条件控制语句) {
循环体语句;
}
-
格式解释:
- 初始化语句: 用于表示循环开启时的起始状态,简单说就是循环开始的时候什么样
- 条件判断语句:用于表示循环反复执行的条件,简单说就是判断循环是否能一直执行下去
- 循环体语句: 用于表示循环反复执行的内容,简单说就是循环反复执行的事情
- 条件控制语句:用于表示循环执行中每次变化的内容,简单说就是控制循环是否能执行下去
-
执行流程:
①执行初始化语句
②执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
③执行循环体语句
④执行条件控制语句
⑤回到②继续
5.5.2 for循环练习-输出数据(应用)
- 需求:在控制台输出1-5和5-1的数据
- 示例代码:
public class ForTest01 {
public static void main(String[] args) {
//需求:输出数据1-5
for(int i=1; i<=5; i++) {
System.out.println(i);
}
System.out.println("--------");
//需求:输出数据5-1
for(int i=5; i>=1; i--) {
System.out.println(i);
}
}
}
5.5.3 for循环练习-求和(应用)
- 需求:求1-5之间的数据和,并把求和结果在控制台输出
- 示例代码:
public class ForTest02 {
public static void main(String[] args) {
//求和的最终结果必须保存起来,需要定义一个变量,用于保存求和的结果,初始值为0
int sum = 0;
//从1开始到5结束的数据,使用循环结构完成
for(int i=1; i<=5; i++) {
//将反复进行的事情写入循环结构内部
// 此处反复进行的事情是将数据 i 加到用于保存最终求和的变量 sum 中
sum += i;
/*
sum += i; sum = sum + i;
第一次:sum = sum + i = 0 + 1 = 1;
第二次:sum = sum + i = 1 + 2 = 3;
第三次:sum = sum + i = 3 + 3 = 6;
第四次:sum = sum + i = 6 + 4 = 10;
第五次:sum = sum + i = 10 + 5 = 15;
*/
}
//当循环执行完毕时,将最终数据打印出来
System.out.println("1-5之间的数据和是:" + sum);
}
}
- 本题要点:
- 今后遇到的需求中,如果带有求和二字,请立即联想到求和变量
- 求和变量的定义位置,必须在循环外部,如果在循环内部则计算出的数据将是错误的
5.5.4 for循环练习-求偶数和(应用)
- 需求:求1-100之间的偶数和,并把求和结果在控制台输出 }
- 示例代码(方法一):
public class ForTest03 {
public static void main(String[] args) {
//求和的最终结果必须保存起来,需要定义一个变量,用于保存求和的结果,初始值为0
int sum = 0;
//对1-100的数据求和与1-5的数据求和几乎完全一样,仅仅是结束条件不同
for(int i=1; i<=100; i++) {
//对1-100的偶数求和,需要对求和操作添加限制条件,判断是否是偶数
if(i%2 == 0) {
sum += i;
}
}
//当循环执行完毕时,将最终数据打印出来
System.out.println("1-100之间的偶数和是:" + sum);
}
}
-
示例代码(方法二):
public class ForTest03 { public static void main(String[] args) { //求和的最终结果必须保存起来,需要定义一个变量,用于保存求和的结果,初始值为0 int sum = 0; //最后每次i直接加2 for(int i=0; i<=100; i+=2) { //这时的i就是 0 2 4..... sum += i; } //当循环执行完毕时,将最终数据打印出来 System.out.println("1-100之间的偶数和是:" + sum); } }
5.5.5 for循环练习-水仙花(应用)
- 需求:在控制台输出所有的“水仙花数”
- 解释:什么是水仙花数?
- 水仙花数,指的是 ①一个三位数 ②个位、十位、百位的数字立方和等于原数
- 例如
153 3*3*3 + 5*5*5 + 1*1*1 = 153
- 例如
- 水仙花数,指的是 ①一个三位数 ②个位、十位、百位的数字立方和等于原数
- 思路:
- 获取所有的三位数,准备进行筛选,最小的三位数为100,最大的三位数为999,使用for循环获取
- 获取每一个三位数的个位,十位,百位,做if语句判断是否是水仙花数
- 示例代码
public class ForTest04 {
public static void main(String[] args) {
//输出所有的水仙花数必然要使用到循环,遍历所有的三位数,三位数从100开始,到999结束
for(int i=100; i<1000; i++) {
//在计算之前获取三位数中每个位上的值
int ge = i%10;
int shi = i/10%10;
int bai = i/10/10%10;
//判定条件是将三位数中的每个数值取出来,计算立方和后与原始数字比较是否相等
if(ge*ge*ge + shi*shi*shi + bai*bai*bai == i) {
//输出满足条件的数字就是水仙花数
System.out.println(i);
}
}
}
}
5.5.6 for循环练习-统计水仙花数个数(应用)
- 需求:统计“水仙花数”一共有多少个,并在控制台输出个数
- 示例代码:
public class ForTest05 {
public static void main(String[] args) {
//定义变量count,用于保存“水仙花数”的数量,初始值为0
int count = 0;
//输出所有的水仙花数必然要使用到循环,遍历所有的三位数,三位数从100开始,到999结束
for(int i=100; i<1000; i++) {
//在计算之前获取三位数中每个位上的值
int ge = i%10;
int shi = i/10%10;
int bai = i/10/10%10;
//在判定水仙花数的过程中,满足条件不再输出,更改为修改count的值,使count+1
if(ge*ge*ge + shi*shi*shi + bai*bai*bai == i) {
count++;
}
}
//打印输出最终结果
System.out.println("水仙花共有:" + count + "个");
}
}
- 本题要点:
- 今后如果需求带有统计xxx,请先想到计数器变量
- 计数器变量定义的位置,必须在循环外部
5.6 循环结构: while循环
5.6.1 while结构(掌握)
-
while循环完整格式:
初始化语句; while (条件判断语句) { 循环体语句; 条件控制语句; }
-
while循环执行流程:
①执行初始化语句
②执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
③执行循环体语句
④执行条件控制语句
⑤回到②继续
-
示例代码:
public class WhileDemo {
public static void main(String[] args) {
//需求:在控制台输出5次"HelloWorld"
//for循环实现
for(int i=1; i<=5; i++) {
System.out.println("HelloWorld");
}
System.out.println("--------");
//while循环实现
int j = 1;
while(j<=5) {
System.out.println("HelloWorld");
j++;
}
}
}
- 什么时候用for?什么时候用while?
- 功能上是完全一样的,for能解决的while也能解决,反之亦然。
- 使用规范:知道循环几次:使用for; 不知道循环几次建议使用:while
5.6.2 while循环练习-珠穆朗玛峰(应用)
- 需求:世界最高山峰是珠穆朗玛峰(8844.43米=8844430毫米),假如我有一张足够大的纸,它的厚度是0.1毫米。请问,我折叠多少次,可以折成珠穆朗玛峰的高度?
- 思路:
- 定义变量存储珠穆朗玛峰的高度、纸张的高度。
- 使用while循环,循环条件是(纸张厚度<山峰高度),内部控制纸张折叠,每折叠一次,纸张厚度为原来两倍,循环外定义计数变量,每折叠一次让该变量+1
- 示例代码:
public class WhileTest {
public static void main(String[] args) {
//定义一个计数器,初始值为0
int count = 0;
//定义纸张厚度
double paper = 0.1;
//定义珠穆朗玛峰的高度
int zf = 8844430;
//因为要反复折叠,所以要使用循环,但是不知道折叠多少次,这种情况下更适合使用while循环
//折叠的过程中当纸张厚度大于珠峰就停止了,因此继续执行的要求是纸张厚度小于珠峰高度
while(paper <= zf) {
//循环的执行过程中每次纸张折叠,纸张的厚度要加倍
paper *= 2;
//在循环中执行累加,对应折叠了多少次
count++;
}
//打印计数器的值
System.out.println("需要折叠:" + count + "次");
}
}
5.7 循环结构:do-while循环
5.7.1 do…while循环结构(掌握)
- 特点:一定会先执行一次循环体。
- 业务场景:例如抢票:先赶紧抢票,抢了之后再看是否买到了。并不会先进行判断是否抢到票了。
-
完整格式:
初始化语句; do { 循环体语句; 条件控制语句; }while(条件判断语句);
-
执行流程:
① 执行初始化语句
② 执行循环体语句
③ 执行条件控制语句
④ 执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
⑤ 回到②继续
-
示例代码:
public class DoWhileDemo {
public static void main(String[] args) {
//需求:在控制台输出5次"HelloWorld"
//for循环实现
for(int i=1; i<=5; i++) {
System.out.println("HelloWorld");
}
System.out.println("--------");
//do...while循环实现
int j = 1;
do {
System.out.println("HelloWorld");
j++;
}while(j<5);
}
}
5.8 三种循环的区别(理解)
- 三种循环的区别
- for循环和while循环先判断条件是否成立,然后决定是否执行循环体(先判断后执行)
- do…while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断)
- for循环和while的区别
- for循环中,控制循环的变量只在循环中可以使用。while循环中,控制循环的变量在循环后还可以继续使用。
- 功能上是完全一样的,for能解决的while也能解决,反之亦然。
- 使用规范:知道循环几次:使用for; 不知道循环几次建议使用:while
5.9 死循环(无限循环)的三种格式
- for(;😉{}
- while(true){}
- do {} while(true);
-
需求:系统密码是520,请用户不断的输入密码验证,验证不对输出密码错误,验证成功输出欢迎进入系统,并停止程序。
-
思路:
- 使用while死循环,让用户不断输入数据
- 与密码比对:验证不成功输出密码错误
- 验证成功输出欢迎进入系统,并使用break结束当前循环的执行。
-
实例代码:
public static void main(String[] args) { //1.定义正确的密码 int okPassword = 520; //2.定义一个死循环让用户不断的输入密码认证 Scanner sc = new Scanner(System.in); while(true){ System.out.println("请你输入正确的密码:"); int password = sc.nextInt(); //3.使用if判断密码是否正确 if(password == okPassword){ System.out.println("登录成功"); break; //立即结束当前所在循环的执行 }else{ System.out.println("密码错误!"); } } }
5.10 跳转控制语句(掌握)
- 跳转控制语句(break)
- 跳出循环,结束循环
- 跳转控制语句(continue)
- 跳过本次循环,继续下次循环
- 注意:
- continue:只能在循环中进行使用!
- break:只能用于结束所在循环,或者结束所在switch分支的执行。
5.11 循环嵌套(理解)
-
循环嵌套概述:在循环中,继续定义循环
-
示例代码:
public static void main(String[] args) { //外循环控制小时的范围,内循环控制分钟的范围 for (int hour = 0; hour < 24; hour++) { for (int minute = 0; minute < 60; minute++) { System.out.println(hour + "时" + minute + "分"); } System.out.println("--------"); } }
-
理解:
- 请反复理解这句话(整个内循环,就是外循环的一个循环体,内部循环体没有执行完毕,外循环是不会继续向下执行的)
-
结论:
- 外循环执行一次,内循环执行一圈
5.12 Random
5.12.1 Random产生随机数(掌握)
-
概述:
- Random类似Scanner,也是Java提供好的API,内部提供了产生随机数的功能
- API后续课程详细讲解,现在可以简单理解为Java已经写好的代码
- Random类似Scanner,也是Java提供好的API,内部提供了产生随机数的功能
-
使用步骤:
-
导入包:告诉程序去JDK的那个包中找随机技术
import java.util.Random;
-
创建对象:得到随机数对象
Random r = new Random();
-
产生(接收)随机数:调用随机数的功能获得0-9的随机数
int num = r.nextInt(10);
解释:10代表的是一个范围,如果括号写10,产生的随机数就是0-9,括号写20,参数的随机数则是0-19
【注】nextInt(n)只能生成:0至n-1之间的随机数,不包含n。
-
-
示例代码:
import java.util.Random;
public class RandomDemo {
public static void main(String[] args) {
//创建对象
Random r = new Random();
//用循环获取10个随机数
for(int i=0; i<10; i++) {
//获取随机数
int number = r.nextInt(10);
System.out.println("number:" + number);
}
//需求:获取一个1-100之间的随机数
int x = r.nextInt(100) + 1;
System.out.println(x);
}
}
【注】Random生成区间随机数的技巧:减加法
//随机数范围是3-17 怎么弄?
//减加法:先减掉3,再加
// 3-17 ->(0-14)+3
r.nextInt(15) + 3;
5.12.2 Random练习-猜数字(应用)
-
需求:
程序自动生成一个1-100之间的数字,使用程序实现猜出这个数字是多少?
当猜错的时候根据不同情况给出相应的提示
A. 如果猜的数字比真实数字大,提示你猜的数据大了
B. 如果猜的数字比真实数字小,提示你猜的数据小了
C. 如果猜的数字与真实数字相等,提示恭喜你猜中了
-
思路:
- 随机生成一个1-100之间的数据
- 使用死循环让用户不断提示用户猜测,猜大提示过大,猜小提示过小,猜中结束游戏。
-
示例代码:
import java.util.Random;
import java.util.Scanner;
public class RandomTest {
public static void main(String[] args) {
//要完成猜数字的游戏,首先需要有一个要猜的数字,使用随机数生成该数字,范围1到100
Random r = new Random();
int number = r.nextInt(100) + 1;
while(true) {
//使用程序实现猜数字,每次均要输入猜测的数字值,需要使用键盘录入实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入你要猜的数字:");
int guessNumber = sc.nextInt();
//比较输入的数字和系统产生的数据,需要使用分支语句。
//这里使用if..else..if..格式,根据不同情况进行猜测结果显示
if(guessNumber > number) {
System.out.println("你猜的数字" + guessNumber + "大了");
} else if(guessNumber < number) {
System.out.println("你猜的数字" + guessNumber + "小了");
} else {
System.out.println("恭喜你猜中了");
break; //结束
}
}
}
}
6.数组
6.1什么是数组【理解】
数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致。
6.2 数组的定义【记忆】
6.2.1 静态初始化数组
-
什么是静态初始化数组?
- 在创建数组时,直接将元素确定
-
定义数组的时候直接给数组赋值
-
格式:数据类型[ ] 数组名 = new 数据类型 [ ]{元素1 , 元素2 , 元素3…}
-
示例1 完整格式:
数据类型[ ] 数组名 = new 数据类型 [ ]{元素1 , 元素2 , 元素3…};
int[] arr = new int[]{2,1,34,56};
double[] arr = new double[]{87.6,76.8,12.3};
char[] arr;
-
示例2 简化格式:
数据类型[ ] 数组名 = {元素1 , 元素2 , 元素3…};
int[] arr = {2,1,34,56};
数组的基本原理:
这个数组名称中,它是否存的是数组对象的地址呢?——是的,根据地址去找这三个元素。
【注】
-
数组变量名中存储的是数组在内存中的地址,数组是引用类型。
-
什么叫引用类型?——它里面存的是地址,通过地址去引用这个对象。
-
引用类型装的是地址,基本数据类型里面通常装的是数据。
1. 数组的访问
什么是索引
每一个存储到数组的元素,都会自动的拥有一个编号,从0开始。
这个自动编号称为数组索引(index),可以通过数组的索引访问到数组中的元素。
访问数组元素格式
数组名[索引];
示例代码
public class ArrayDemo {
public static void main(String[] args) {
int[] arr = new int[3];
//输出数组名
System.out.println(arr); //[I@880ec60
//输出数组中的元素
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
}
}
- 如何访问数组里面的元素?
- 根据数组名的地址去找数组,再根据索引定位是哪个元素。
- 格式:
- 取值:数组名称 [索引]
- 赋值:数组名称 [索引] = 数据
- 访问数组长度:数组名称.length
- 数组的最大索引可以怎么表示?
- 数组名称.length - 1 //前提:元素个数大于0
2. 数组的注意事项
6.2.2 动态初始化数组
1. 什么是动态初始化
定义数组的时候只确定元素的类型和数组的长度,之后再存入具体数据。
2. 动态初始化格式
数据类型[] 数组名 = new 数据类型[数组长度];
int[] arr = new int[3];
3. 动态初始化格式详解
-
等号左边:
-
int:数组的数据类型
-
[]:代表这是一个数组
-
arr:代表数组的名称
-
-
等号右边:
- new:为数组开辟内存空间
-
int:数组的数据类型
-
[]:代表这是一个数组
-
5:代表数组的长度
4.两种数组有什么区别?
- 当前已经知道存入的元素值,用静态初始化。
- 当前还不清楚要存入那些数据,用动态初始化。
5.动态初始化数组的元素默认值
6.3 数组遍历【应用】
-
遍历:就是一个一个数据的访问。
-
为什么要遍历?搜索、数据统计等等都需要用到遍历。
public class ArrayTest01 { public static void main(String[] args) { int[] arr = { 1, 2, 3, 4, 5 }; System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); System.out.println(arr[3]); System.out.println(arr[4]); } }
以上代码是可以将数组中每个元素全部遍历出来,但是如果数组元素非常多,这种写法肯定不行,因此我们需要改造成循环的写法。数组的索引是 0 到 lenght-1 ,可以作为循环的条件出现。
public class ArrayTest01 { public static void main(String[] args) { //定义数组 int[] arr = {11, 22, 33, 44, 55}; //使用通用的遍历格式 for(int x = 0; x < arr.length; x++) { System.out.println(arr[x]); } } }
6.4 数组案例【应用】
6.4.1 数组元素求和
-
需求:某部门5名员工的销售额分别是16、26、36、6、100,请计算出他们部门的总销售额。
-
思路:
-
把这5个数据拿到程序中去–>使用数组
【即 使用数组存储批量数据】
int[] money = {16,26,36,6,100};
-
遍历数组中的每个数据,然后在外面定义求和变量把他们累加起来。
int sum = 0; for (int i = 0;i < money.length;i++){ // i = 0 1 2 3 4 sum += money[i]; }
-
-
案例代码:
public static void main(String[] args) { //1.把这5个数据拿到程序中使用数组 int[] money = {16,26,36,6,100}; //3.定义一个求和变量累加数组的元素值 int sum = 0; //2.遍历数组中的每个元素 for(int i = 0; i < money.length;i++){ //拿到每个元素值累加 sum += money[i]; } //4.输出求和变量 System.out.println("数组的元素和是:"+sum); }
6.4.2 数组最值
-
需求:从数组的所有元素中找出最大值。
-
思路:
- 把数据拿到程序中去,用数组装起来。
- 定义一个变量用于记录最大值,这个变量建议默认存储第一个元素值作为参照。
- 遍历数组的元素,如果该元素大于变量存储的元素,则替换变量存储的值为该元素。
- 循环结束后输出最大值变量即可。
-
案例代码:
public class ArrayTest02 { public static void main(String[] args) { //定义数组 int[] arr = {12, 45, 98, 73, 60}; //定义一个变量,用于保存最大值 //取数组中第一个数据作为变量的初始值 int max = arr[0]; //与数组中剩余的数据逐个比对,每次比对将最大值保存到变量中 for(int x=1; x<arr.length; x++) { if(arr[x] > max) { max = arr[x]; } } //循环结束后打印变量的值 System.out.println("max:" + max); } }
6.4.3 猜数字游戏
-
需求:开发一个幸运小游戏,游戏规则如下:
- 游戏后台随机生成1-20之间的5个数(无所谓是否重复),然后让大家来猜数字
- 未猜中提示:“未命中”,并继续猜测
- 猜中提示:“运气不错,猜中了”,并输出该数据第一次出现的位置,且输出全部5个数据,最终结束本游戏。
-
思路:
- 随机生成5个1-20之间的数据,用数组【动态数组】装起来。
- 定义一 个死循环,输入数据猜测,遍历数组,判断数据是否在数组中,如果在,进行对应提示并结束死循环;如果没有猜中,提示继续猜测直到猜中为止。
-
案例代码:
public class ArrayTest02 { public static void main(String[] args) { //1.定义一个动态初始化的数组存储5个随机的1-20之间的数据 int[] data = new int[5]; //2.动态的生成5个1-20之间的随机数并存入到数组中去 Random r = new Random(); for(int i=0; i<data.length; i++) { // i = 0 1 2 3 4 data[i] = r.nextInt(20) + 1; //随机数范围是1-20 } //3.使用死循环,让用户进行猜测 Scanner sc = new Scanner(System.in); OUT: while(true){ System.out.println("请输入1-20之间的整数进行猜测:"); int guessData = sc.nextInt(); //4.遍历数组中的每个数据,看是否与猜测的数据相同 for(int i = 0;i < data.length;i++){ if(data[i] == guessData){ System.out.println( "恭喜,猜中了!你猜中的数据索引是:"+i); break OUT;//结束了整个死循环,代表游戏结束了 //如果这里只写break,说明只结束了for循环,并没有结束while循环 } } System.out.println("当前猜测的数据在数组中不存在,请重新猜测"); } //5.输出数组所有元素,让用户看到自己确实是猜中了某个数据。 for(int i = 0;i < data.length;i++){ System.out.print(data[i]+"\t"); //打印一行 } } }
6.4.4 随机交换排名
-
需求:某公司开发部5名开发人员,要进行项目进展汇报演讲,现在采取随机排名后进行汇报。
-
请先依次录入5名员工的工号,然后展示出一组随机的排名顺序。
-
22 33 35 13 88 ——> 13 35 88 33 22
-
思路:
- 在程序中录入5名员工的工号存储起来,用数组【动态数组】装起来。
- 依次遍历数组中的每个元素,随机一个索引数据,让当前元素与该索引位置处的元素进行交换。
-
案例代码:
public static void main(String[] args) { //1.动态初始化一个数组,存储5个工号 int[] codes = new int[5]; //2.定义一个循环,循环5次,依次录入一个工号存入对应的位置 Scanner sc = new Scanner(System.in); for(int i=0; i< codes.length; i++) { // i = 0 1 2 3 4 //正式录入工号 System.out.println("请输入第"+(i+1)+"个员工的工号:"); int code = sc.nextInt(); //存入到数组中去 codes[i] = code; } //3.遍历数组中的每个元素,然后随机一个索引出来,让该元素与随机索引位置处的元素值进行交换【重点】 Random r = new Random(); for(int i=0; i< codes.length; i++) { //当前遍历的元素值:codes[i] //例如 codes = [12,33,45,67] 长度是4 索引范围是0-3 int index = r.nextInt(codes.length); //定义一个临时变量存储index位置处的值 int temp = codes[index]; codes[index] = codes[i]; codes[i] = temp; } //4.遍历数组元素输出就是随机排名的结果 for(int i=0; i< codes.length; i++) { System.out.print(codes[i]+ "\t"); } }
-
随机交换排名的使用场景:斗地主洗牌
6.4.5 数组排序
- 冒泡排序
6.5 数组的内存图【理解】
6.5.1 Java内存分配、数组内存图
-
Java 内存分配介绍
- 栈
- 堆
- 方法区
- 由这三块区域配合去执行这Java程序的!
-
目前我们只需要记住两个内存,分别是:栈内存和堆内存
区域名称 | 作用 |
---|---|
寄存器 | 给CPU使用,和我们开发无关。 |
本地方法栈 | JVM在使用操作系统功能的时候使用,和我们开发无关。 |
方法区 | 存储可以运行的class文件。 |
堆内存 | 存储对象或者数组,new来创建的,都存储在堆内存。 |
方法栈 | 方法运行时使用的内存,比如main方法运行,进入方法栈中执行。 |
6.5.2 两个变量指向同一个数组
6.6 数组使用的常见问题【应用】
6.6.1 问题1:索引越界异常
- 如果访问的元素位置超过最大索引,执行时会出现 ArrayIndexOutOfBoundsException (数组索引越界异常)
-
出现原因
public class ArrayDemo { public static void main(String[] args) { int[] arr = new int[3]; System.out.println(arr[3]); } }
数组长度为3,索引范围是0~2,但是我们却访问了一个3的索引。
程序运行后,将会抛出ArrayIndexOutOfBoundsException 数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。
-
解决方案
将错误的索引修改为正确的索引范围即可!
6.6.2 问题2:空指针异常
- 如果数组变量中没有存储数组的地址,而是null,在访问数组信息时会出现NullPointerException (空指针异常)
-
出现原因
public class ArrayDemo { public static void main(String[] args) { int[] arr = new int[3]; //把null赋值给数组 arr = null; System.out.println(arr[0]); } }
arr = null 这行代码,意味着变量arr将不会再保存数组的内存地址,也就不允许再操作数组了,因此运行的时候会抛出 NullPointerException 空指针异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。
-
解决方案
给数组一个真正的堆内存空间引用即可!
6.7 debug工具
7. 方法概述
7.1 方法的概念(理解)
方法(method)是一种语法结构,它可以把一段代码封装成一个功能,以方便重复调用。
- 使用方法的好处:
- 提高了代码的复用性。
- 让程序的逻辑更清晰。
原本:
现在:定义同样相加的方法
- 注意:
- 方法必须先创建才可以使用,该过程成为方法定义,但方法有不同形式的写法,要在不同的业务场景下写出合适的方法形式。
- 方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用,方法定义出来是拿来调用的,只有调用才能让方法跑起来。
7.2 方法的定义和调用
7.2.1 方法定义的完整格式
-
方法格式的注意点
- 方法的修饰符:暂时都使用public static修饰。
- 方法申明了具体的返回值类型,内部必须使用return返回对应类型的数据。
- 形参列表可以有多个,甚至可以没有;如果有多个形参,多个形参必须用“,”隔开,且不能初始化值。
-
总结:
7.2.2 其他形式的方法定义、调用
- 方法定义时:返回值类型、形参列表可以按照需求进行填写。
- 如果方法不需要返回结果,返回值类型必须申明成void(无返回值),此时方法内部不可以使用return返回数据。
- 方法如果没有参数,或者返回值类型申明为void可以称为无参数、无返回值的方法,依次类推。
7.2.3 无参数方法的练习(应用)
- 需求:设计一个方法用于打印两个数中的较大数
- 思路:
- ①定义一个方法,用于打印两个数字中的较大数,例如getMax()
- ②方法中定义两个变量,用于保存两个数字
- ③使用分支语句分两种情况对两个数字的大小关系进行处理
- ④在main()方法中调用定义好的方法
- 代码:
public class MethodTest {
public static void main(String[] args) {
//在main()方法中调用定义好的方法
getMax();
}
//定义一个方法,用于打印两个数字中的较大数,例如getMax()
public static void getMax() {
//方法中定义两个变量,用于保存两个数字
int a = 10;
int b = 20;
//使用分支语句分两种情况对两个数字的大小关系进行处理
if(a > b) {
System.out.println(a);
} else {
System.out.println(b);
}
}
}
7.2.4 形参和实参(理解)
- 形参:方法定义中的参数
等同于变量定义格式,例如:int number
- 实参:方法调用中的参数
等同于使用变量或常量,例如: 10 number
7.2.5 带参数方法练习(应用)
- 需求:设计一个方法用于打印两个数中的较大数,数据来自于方法参数 }
- 思路:
- ①定义一个方法,用于打印两个数字中的较大数,例如getMax()
- ②为方法定义两个参数,用于接收两个数字
- ③使用分支语句分两种情况对两个数字的大小关系进行处理
- ④在main()方法中调用定义好的方法(使用常量)
- ⑤在main()方法中调用定义好的方法(使用变量)
- 代码:
public class MethodTest {
public static void main(String[] args) {
//在main()方法中调用定义好的方法(使用常量)
getMax(10,20);
//调用方法的时候,人家要几个,你就给几个,人家要什么类型的,你就给什么类型的
//getMax(30);
//getMax(10.0,20.0);
//在main()方法中调用定义好的方法(使用变量)
int a = 10;
int b = 20;
getMax(a, b);
}
//定义一个方法,用于打印两个数字中的较大数,例如getMax()
//为方法定义两个参数,用于接收两个数字
public static void getMax(int a, int b) {
//使用分支语句分两种情况对两个数字的大小关系进行处理
if(a > b) {
System.out.println(a);
} else {
System.out.println(b);
}
}
}
7.3 方法使用的常见问题 ( 掌握 )
-
方法的编写顺序无所谓,写在main方法前面或者后面都可以。
-
方法与方法之间是平级关系,不能嵌套定义。
-
方法的返回值类型为void(无返回值),方法内则不能使用return返回数据,如果方法的返回值类型写了具体类型,方法内部则必须使用return返回对应类型的数据。
-
return语句下面,不能编写代码,因为永远执行不到,属于无效代码。
-
方法不调用就不执行,调用时必须严格匹配方法的参数情况。
-
有返回值的方法调用时可以选择定义变量接收结束,或者直接输出调用,甚至直接调用
-
无返回值方法的调用只能直接调用一下。
7.4 方法案例
7.4.1 定义方法的技巧、计算 1 - n 的和返回
-
需求:定义一个方法,方法中计算 1-n 的和并返回。
-
思路:
-
根据格式编写方法 ----> 因n不固定,故方法需要声明形参接收;要返回结果,还需申明返回值类型。
-
方法内部使用 for 循环计算出 1-n 的和并返回。
-
遍历数组的元素,如果该元素大于变量存储的元素,则替换变量存储的值为该元素。
-
-
案例代码:
public class ArrayTest02 { public static void main(String[] args) { System.out.println("1-5的和是:"+sum(5)); System.out.println("1-100的和是:"+sum(100)); } public static int sum(int n){ int sum = 0; for(int i=1; i <= n; i++) { sum += i; } return sum; } }
7.4.2 判断整数是奇数还是偶数
-
需求:拿一个整数,然后调用方法,把整数交给方法,在方法中输出该数为奇数还是偶数。
-
思路:
- 根据格式编写方法 ----> 因要传入数据给方法,方法需要声明形参接收。
- 方法内部使用 if 语句判断,并输出对应的结论。
-
案例代码:
public class ArrayTest02 { public static void main(String[] args) { check(10); check(5); } public static void check(int number){ if(number % 2 ==0 ){ System.out.println(number+"是偶数"); }else{ System.out.println(number+"是奇数"); } }
7.4.3 数组求最值案例改方法实现
-
需求:把找出数组的最大值案例,改造成方法,可以支持返回任意整型数组的最大值数据。
-
思路:
- 根据格式编写方法。
- 要返回最大值,需要申明返回值类型。
- 需要接收数组,需要申明形参列表。
- 方法内部找出数组的最大值并返回。
- 根据格式编写方法。
-
案例代码:
public class ArrayTest02 { public static void main(String[] args) { int[] ages = {23,6,35,77}; int max = getArrayMaxData(ages); System.out.println("最大值是:"+max); } public static int getArrayMaxData(int[] arr){ //传过来接收的是数组地址 //找出数组的最大值返回 int max = arr[0]; //用数组第一个值作为参照 //遍历数组的每个元素与最大值的数据进行比较,若较大则替换 // 因为第一个数组元素作为参照了,那么从第二个元素i=1开始 for(int i=1; i <= arr.length; i++) { if(arr[i] > max){ max = arr[i]; } } return max; } }
7.5 方法调用的内存图(理解)
- 方法没有被调用的时候,在方法区中的字节码文件中存放
- 方法被调用的时候,需要进入到栈内存中运行
再看一个内存图解!
7.6 方法的参数传递机制
7.6.1 基本类型的参数传递
-
Java的参数传递机制:值传递
-
在传输实参给方法的形参的时候,并不是传输实参变量本身,而是传输实参变量中存储的值,这就是值传递。
-
注意
- 实参:如在方法内部定义的变量。
- 形参:如在定义方法时,“( )”中所声明的参数。
-
面试题
7.6.2 引用类型的参数传递
- 基本类型和引用类型的参数在传递时有什么不同?
- 两者都是值传递
- 基本类型传递的是里面存储的数据值
- 引用类型传递的是里面存储的地址值
7.7 方法的参数传递案例
7.7.1 数组遍历(应用)
-
需求:设计一个方法用于输出任意整型数组的内容,要求输出成如下格式:“该数组内容为:[11, 22, 33, 44, 55] ”
-
思路:
- 定义一个方法,要求该方法能够接收数组,并输出数组内容。
- 定义一个静态初始化的数组,调用该方法,并传入该数组。
-
代码:
public class MethodTest01 { public static void main(String[] args) { //定义一个数组,用静态初始化完成数组元素初始化 int[] arr = {11, 22, 33, 44, 55}; //调用方法 printArray(arr); } //定义一个方法,用数组遍历通用格式对数组进行遍历 /* 两个明确: 返回值类型:void 参数:int[] arr */ public static void printArray(int[] arr) { System.out.print("["); for(int x=0; x<arr.length; x++) { if(x == arr.length-1) { //到最后一个元素就不要再拼贴这个逗号',' System.out.print(arr[x]); } else { System.out.print(arr[x]+", "); //其他情况是要拼贴这个逗号',' } //上面的 if-else 可以用三元运算符,如下: System.out.print(x == arr.length - 1 ? arr[i] : arr[x]+", "); } System.out.println("]"); } }
7.7.2 从数组中查询元素的索引返回
- 需求:设计一个方法可以接收整型数组,和要查询的元素值;最终要返回元素在该数组中的索引,如果数组中不存在该元素则返回 -1。
-
思路:
- 定义一个方法,接收整型数组,查询的元素值,在方法体中完成元素查询的功能。
- 定义数组,调用该方法,并指定要搜索的元素值,得到返回的结果输出。
-
代码:
public static void main(String[] args) {
//定义数组
int[] arr = {11, 22, 33, 44, 55};
//调用方法
int index = searchIndex(arr,55);
System.out.println("查询的数据索引是:"+index);
}
//1.定义一个方法,参数接收数组,要查询的数据,返回值:整型
public static int searchIndex(int[] arr,int data) {
//2.开始找出这个数据的索引
for(int i=0; i<arr.length; i++) {
if(arr[i] == data) {
return i;
}
}
return -1; //查无此元素!
}
7.7.3 比较两个数组内容是否相等
-
需求:如果两个数组的类型,元素个数,元素顺序和内容是一样的,我们就认为这2个数组是一模一样的。
请使用方法完成:能够判断任意两个整型数组是否一样,并返回true或者false。
-
思路:
- 定义方法,接收2个整型数组。
- 在方法内部完成判断的逻辑,并返回布尔结果。
-
代码:
public static void main(String[] args) {
//定义数组
int[] arr1 = {11, 22, 33, 44, 55};
int[] arr2 = {11, 22, 33, 44, 55};
//调用方法
compare(arr1,arr2);
}
//1.定义一个方法,参数:接收2个整型数组,返回值类型:布尔类型
public static boolean compare(int[] arr1,int[] arr2) {
//2.判断2个数组的内容是一样的,首先2个数组的长度是一致的
if(arr1.length == arr2.length){
for(int i=0; i < arr1.length; i++) {
if(arr1[i] != arr2[i]) { //只要有一个位置元素不同,则两个数组不同
return false;
}
}
return true;
}else{
return false;
}
}
7.8 方法重载(重要)
7.8.1 方法重载的形式、作用
-
方法重载:同一类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法。
-
案例导学:
-
开发武器系统,功能需求如下:
- 可以默认发一枚武器。
- 可以指定地区发射一枚武器。
- 可以指定地区发射多枚武器。
-
-
方法重载的作用:可读性好,方法名称相同提示是同一类型的功能,通过形参不同实现功能差异化的选择,这是一种专业的代码设计。
7.8.2 方法重载的识别技巧
-
只要是同一类中,方法名称相同、形参列表不同,那么他们就是重载的方法,其他都不管!(如:修饰符、返回值类型都无所谓)
-
形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。
-
方法重载至少是两个方法。
7.9 补充:单独使用return关键字
- 可以立即跳出并结束当前方法的执行。
- 可以单独使用,可以放在任何方法中。
- break; 、 return; 、continue; 的不同
- break; 跳出并结束当前所在循环的执行。
- return; 跳出并立即结束所在方法的执行。
- continue; 结束当前所在循环的当次继续,进入下一次执行。
8.编程案例
8.1 案例1:买飞机票
- 需求:
- 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。
- 按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)头等舱7折,经济舱6.5折。
- 思路:
- 键盘录入机票原价、月份和机舱类型。
- 使用if判断月份是旺季还是淡季,使用switch分支判断是头等舱还是经济舱。
- 选择对应的折扣进行计算并返回计算的结果。
- 代码:
public class Test01 {
public static void main(String[] args) {
//3.录入购买信息,调用方法得到最终结果
Scanner sc = new Scanner;
System.out.println("机票原价:");
double price = sc.nextDouble();
System.out.println("月份:");
int month = sc.nextInt();
System.out.println("仓位类型(头等舱、经济舱):");
String type = sc.next();
double rs = calc(price,month,type);
System.out.println("当前购买的价格是:"+rs);
}
// 1.定义一个方法: 形参(原价、月份、头等舱经济舱) 返回值类型申明:double
public static double calc(double money,int month,String type){
//2.判断月份是淡季还是旺季
if(month >= 5 && month <= 10){
//旺季
switch(type){
case "经济舱":
money *= 0.85;
break;
case "头等舱":
money *= 0.9;
break;
default:
System.out.println("输入的仓位不正确");
money = -1; //当前无法计算价格了!
}
}else if(month == 11 || month == 12 || month >= 1 && month <= 4){
switch(type){
case "经济舱":
money *= 0.65;
break;
case "头等舱":
money *= 0.7;
break;
default:
System.out.println("输入的仓位不正确");
money = -1; //当前无法计算价格了!
}
}else{
System.out.println("月份有问题");
money = -1; //当前无法计算价格了!
}
return money;
}
}
8.2 案例2:找素数
-
需求:
- 判断101 - 200 之间有多少个素数,并输出所有素数。
- 素数:如果除了1和它本身以外,不能被其他正整数整除,就叫素数。
-
思路:
- 101 - 200之间的数据可以采用循环依次拿到;每拿到一个数,判断该数是否是素数。
- 判断规则是:从2开始遍历到该数的一半的数据,看是否有数据可以整除它,有则不是素数,没有则是素数。
-
代码:
public class Test02 {
public static void main(String[] args) {
//1.定义一个循环,找到101 - 200 之间的全部数据
for(int i=101; i <= 200; i++) {
//信号位:标记
boolean flag = true; //一开始认为当前数据是素数
//2,判断当前数据是否是素数
for(int j=2; j < (i/2); j++){
if(i % j == 0){ //发现可以前半部分数可以整除i,则不是素数
flag = false ;
break;
}
}
//3. 根据判定的结果选择是否输出这个数据,是素数则输出
if(flag) { //flag是true说明就是素数,那么输出这个数
System.out.print(i+"\t");
}
}
}
}
8.3 案例3:开发验证码
-
需求:
- 定义方法实现随机产生一个5位的验证码,每位可能是数字、大写字母、小写字母。
-
思路:
- 定义一个方法,生成验证码返回;方法参数是位数、方法的返回值类型是String。
- 在方法内部使用for循环生成指定位数的随机字符,并连接起来。
- 把连接好的随机字符作为一组验证码进行返回。
-
代码:
public class Test03 {
public static void main(String[] args) {
//4.调用获取验证码的方法得到一个随机的验证码
String code = createCode(5);
System.out.println("随机验证码:"+code);
}
//1、定义一个方法返回一个随机验证码: 是否需要返回值类型申明? String 是否需要申明形参: int n
public static String createCode(int n){
//3.定义一个字符串变量记录生成的随机字符
String code = "";
Random r = new Random();
// 2、定义一个for循环,循环n次,依次生成随机字符
for (int i = 0;i< n; i++) {
// 3、生成一个随机字符:数字、大写字母、小写字母
int type = r.nextInt(3); // 0 1 2
switch (type){
case 0:
//大写字符(A 65 - Z 65+25) 范围 (0-25)+65 字符是char
char ch = (char) (r.nextInt(26)+65);
code += ch;
break;
case 1:
//小写字符(a 97 - Z 97+25) 范围 (0-25)+97
char ch1 = (char) (r.nextInt(26)+97);
code += ch1;
break;
case 2:
//数字字符
code += r.nextInt(10); //0 - 9
break;
}
}
return code;
}
}
8.4 案例4:数组的复制
-
需求:
- 把一个数组中的元素复制到另一个新数组中去。
-
思路:
- 需要动态初始化一个数组,长度与原数组一样。
- 遍历原数组的每个元素,依次赋值给新数组。
-
输出两个数组的内容。
-
代码:
public class Test4 {
public static void main(String[] args) {
int[] arr1 = {11,22,33,44};
// int[] arr2 = arr1; //这种不是数组复制 只是复制了arr1地址 arr2也指向了arr1 内存中只有一个数组
int[] arr2 = new int[arr1.length];
copy(arr1,arr2);
printArray(arr1);
printArray(arr2);
}
public static void copy(int[] arr1,int[] arr2){
//元素复制
for(int i=0; i<arr1.length; i++) {
arr2[i] = arr1[i];
}
}
public static void printArray(int[] arr){
System.out.print("[");
for(int i=0; i<arr.length; i++) {
System.out.print(i == arr.length - 1 ? arr[i] : arr[i]+",");
}
System.out.println("]");
}
}
8.5 案例5:评委打分
-
需求:
- 在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。
- 选手的最后得分为:去掉一个最高分和一个最低分后 的4个评委平均值 (不考虑小数部分)。
-
思路:
- 把6个评委的分数录入到程序中去,使用动态数组。
- 遍历数组每个数据,进行累加求和,并找到最高分、最低分。
- 按照分数的计算规则算出平均分。
-
代码:
public class Test5 {
public static void main(String[] args) {
//1.定义一个数组,用动态初始化完成数组元素的初始化,长度为6
int[] arr = new int[6];
//2.键盘录入评委分数
Scanner sc = new Scanner(System.in);
//由于是6个评委打分,所以,接收评委分数的操作,用循环改进
for(int x=0; x<arr.length; x++) {
System.out.println("请输入第" + (x + 1) + "个评委的打分:");
int score = sc.nextInt();
//3.把这个分数存入到数组的对应位置处
arr[i] = score;
}
//4.遍历数组中每个值,找出最大值,最小值、总分
int max = arr[0];
int min = arr[0];
int sum = 0;
for(int i=0; i<arr.length; i++) { //因为这里要统计总和 所以这里i从0开始
if(arr[i] < min) {
//替换最小值变量存储的数据
min = arr[i];
}
if(arr[i] > max) {
//替换最大值变量存储的数据
max = arr[i];
}
//统计总分
sum += arr[i];
}
System.out.println("选手的最高分是:" + max);
System.out.println("选手的最低分是:" + min);
//5.统计平均分
double result = (sum-max-min)*1.0/(arr.length - 2);
System.out.println("选手的最终得分是:" + result);
}
}
8.6 案例6:数字加密
-
需求:
-
某系统的数字密码,比如1983,采用加密方式进行传输,规则如下:先得到每位数,然后每位数都加上5,再对10求余,最后将所有数字反转,得到一串新数。
-
-
思路:
- 将每位数据存入到数组中去,遍历数组每位数据按照规则进行更改,把更改后的数据从新存入到数组中。
- 将数组的前后元素进行交换,数组中的最终元素就是加密后的结果。
-
代码:
public class Test6 {
public static void main(String[] args) {
//1.定义一个数组存储需要加密的数据
int[] arr = new int[]{1,9,8,3};
//2.遍历数组中的每个数据,按照规则进行修改
for(int i=0; i<arr.length; i++) {
arr[i] = (arr[i] + 5) % 10;
}
//3.把数组中的数据进行反转操作
for(int i = 0,j = arr.length - 1 ; i < j; i++,j--) {
//交换i和j位置处的值即可
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
//4.遍历数组中每个元素,输出即可
for(int i=0; i<arr.length; i++) {
System.out.print(arr[i]);
}
}
}
9.面向对象编程
- 面向就是拿或找的意思。
- 对象就是东西的意思。
- 面向对象编程就是拿或找东西过来编程。
9.1 设计对象并使用(理解)
9.1.1 设计类,创建对象并使用
-
在Java中,必须先设计类,才能获得对象。
-
类(可以看出是设计图):是对象共同特征的描述
-
对象(也叫实例):是真实存在的具体实例。
-
类里可以写什么【5大部分】?
- 成员变量(代表属性,一般是名词)
- 成员方法(代表行为,一般是动词)
- 构造器
- 代码块
- 内部类
-
总结
![在这里插入图片描述](https://img-blog.csdnimg.cn/0e1dce7721114b57b55d3674236005e0.png)
-
9.1.2 定义类的几个补充注意事项
-
成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始化值 ; 一般无需指定初始化值,存在默认值。修饰符可以不写。
-
类名首字母建议大写,且有意义,满足“驼峰模式”,不能用关键字,满足标志符规定。
-
一个Java文件中可以定义多个class类,且只能一个类是public修饰,而且public修饰的类名必须成为代码文件名。实际开发中建议还是一个文件定义一个class类。
9.2 对象内存图(理解)
9.2.1 多个对象的内存图
-
总结:
9.2.2 两个变量指向同一个对象内存图
- 垃圾回收
- 注意:当堆内存中的类对象或数组对象,没有被任何变量引用(指向)时,就会被判定为内存中的**“垃圾”**。
- Java存在自动垃圾回收器,会定期进行清理。
9.3 构造器(重要)
-
构造器的作用
-
用于初始化一个类的对象,并返回对象的地址。
-
-
构造器的定义格式
-
无参数构造器(默认存在的)
- 初始化的对象时,成员变量的数据均采用默认值。
-
有参数构造器
- 在初始化对象的时候,同时可以为对象进行赋值。
-
-
注意事项
- 任何类定义出来,默认就自带了无参数构造器,写不写都有。
- 一旦定义了有参数构造器,无参数构造器就没有了,此时就需要自己写一个无参数构造器了。
9.4 this关键字(掌握)
- 作用
- 出现在成员方法、构造器中代表当前对象的地址,用于访问当前对象的成员变量、成员方法。
9.4.1 this出现在有参数构造器中的用法
-
这时候就可以使用this,来告知那个是当前全局变量!
![在这里插入图片描述](https://img-blog.csdnimg.cn/4766611ad83e4eff9b3b6b7f7c49b0d1.png)
9.4.2 this出现在成员方法中的用法
9.5 封装
-
面向对象的三大特征:封装、继承、多态。
-
什么是封装?
-
隐藏实现细节,暴露出合适的访问方式。(合理隐藏、合理暴露)
-
-
封装的实现步骤
-
一般对成员变量实现private(私有)关键字修饰进行隐藏,private修饰后该成员变量就只能在当前类中访问【也就是说,在其他地方不能直接去点它】。
这样发现除能在当前类使用,其他相当于完全不能使用它了,太保护也不行!因此,结合下面方法!
-
提供public修饰的公开的getter、setter方法暴露其取值和赋值。
-
总结步骤如下:
- 一般会把成员变量使用private隐藏起来。
- 通过getter和setter方法暴露其访问。
-
-
封装的好处:
- 加强了程序代码的安全性。
- 适当的封装可以提升开发效率,同时可以让程序更容易理解与维护。
9.6 标准JavaBean
-
Javabean:
- 也可以理解成实体类,其对象可以用于在程序中封装数据。
- 实体类:在现实中能找到实际的个体,例如:老师类、汽车类等等。但Test类属于测试类。
- 封装数据:可以理解成创建学生对象就可以封装学生信息,创建汽车对象就可以封装汽车信息等等。
- 也可以理解成实体类,其对象可以用于在程序中封装数据。
-
标准Javabean须满足如下要求:
- 成员变量使用 private 修饰。
- 提供每个成员变量对应的 setxxx() 和 getxxx() 。
- 必须提供一个无参构造器。
-
在idea中直接生成getter和setter方法:
- 右键 -> Generate -> Getter and Setter
- 或:Alt+Insert -> Getter and Setter
-
在idea中直接生成有参构造器的方法:
- 右键 -> Generate -> Constructor
- 或:Alt+Insert -> Constructor
【注意】写了有参构造器之后无参构造器就消失了! 要用无参构造器就得写出来。
-
代码使用
9.7 补充:成员变量、局部变量区别
9.8 面向对象实战:购物车案例(没使用标准Javabean)
-
需求:
- 模拟购物车模块的功能,需要实现添加商品到购物车中去,同时需要提供修改商品的购买数量,结算商品价格功能(请使用面向对象编程来解决)。
- 让用户输入商品信息,并添加到购物车中去,且可立即查看购物车信息。
- 让用户输入商品id,找出对应的商品修改其购买数量。
- 当用户输入pay命令后,需要展示全部购买的商品信息和总金额。
-
分析:
- 购物车中的每个商品都可以看出是一个个对象,需要定义一个商品类,后期创建对象代表一个商品信息。
- 购物车本身也是一个对象;可以使用数组对象代表它。[购物车相当于是个容器,要放很多商品对象]
- 购物车可以使用商品类型的数组对象表示,用于存放商品对象。
- 完成界面架构,让用户选择操作的功能(添加、查看、修改数量、结算价格)。
- 如何完成添加商品功能?
- 需要让用户录入商品信息,创建商品对象封装商品信息。
- 创建Goods类的对象代表商品对象,封装用户输入的商品信息
- 并把商品对象加入到购物车数组中去。
- 需要让用户录入商品信息,创建商品对象封装商品信息。
- 如何查看购物车信息?
- 遍历购物车的数组,每遍历到一个商品对象输出其信息展示。
- 遍历到null,则遍历结束。
- 如何修改商品购买的数量?
- 根据用户输入的商品id查询出要修改的商品对象。
- 如何进行商品的订单总额计算?
- 定义求和变量,遍历购物车数组中的全部商品,累加其单价*购买数量。
-
代码:
-
商品类 Goods.java
public class Goods { int id; //编号 String name; //名称 double price; //价格 int buyNumber; //购买数量 }
-
购物车实现类 ShopCar.java
import java.util.Scanner; public class ShopCarTest { public static void main(String[] args) { //1.定义商品类,用于后期创建商品对象 //2.定义购物车对象,使用一个数组对象表示 // 这里用数组,严格来讲不能用数组,因为购物车无上限,后面会使用集合 // 数组当商品对象 商品对象的类型是Goods 即:定义的商品类 // 类本身也是个类型,引用类型! Goods[] shopCar = new Goods[100]; //[null,null...] //3.搭建操作架构 while (true) { System.out.println("请选择如下命令进行操作:"); System.out.println("添加商品到购物车:add"); System.out.println("查看购物车商品展示:query"); System.out.println("修改商品的数量:update"); System.out.println("结算购买商品的金额:pay"); Scanner sc = new Scanner(System.in); System.out.println("请输入命令:"); String command = sc.next(); switch (command){ case "add": //添加商品到购物车,并把上面的扫描器送入这个方法里,这样方法就不用再新new了 addGoods(shopCar,sc); //这个方法首先接购物车(shop),把购物车给他才能往里添加商品 break; case "query": //查看购物车商品展示 queryGoods(shopCar); //把购物车传给他,才能展示商品 break; case "update": //修改商品的数量 updateGoods(shopCar,sc); break; case "pay": //结算购买商品的金额 payGoods(shopCar); break; default: System.out.println("没有该功能!"); } } } /** * 展示购物车中的全部商品信息和总金额 * */ public static void payGoods(Goods[] shopCar) { //展示购物车全部商品信息 queryGoods(shopCar); // 1.定义求和变量,累加金额 double money = 0; // 2.遍历购物车数组中的全部商品对象,累加:单价*数量 for (int i = 0; i < shopCar.length; i++) { Goods g = shopCar[i]; if (g != null){ money += (g.price* g.buyNumber); }else{ // 一旦遍历到null位置 直接结束循环 break; } } System.out.println("总金额:"+money); } /** * 修改购物车中的商品购买数量 * */ public static void updateGoods(Goods[] shopCar,Scanner sc) { // 让用户输入需要修改的商品id,根据id查询出要修改的商品对象[另写一个方法类] while (true) { System.out.println("请输入要修改的商品id:"); int id = sc.nextInt(); Goods g = getGoodsById(shopCar,id); //返回商品对象 if (g == null){ //没有该商品 System.out.println("不存在该商品,"); }else{ //存在该商品对象,可以修改它 System.out.println("请输入"+g.name+"商品最新购买数量:"); int buyNumber = sc.nextInt(); g.buyNumber = buyNumber; System.out.println("修改完成!"); queryGoods(shopCar); //修改完成后,展示新修改后的购物车信息 break; //商品修改完成,结束循环 } } } public static Goods getGoodsById(Goods[] shopCar,int id){ //返回商品对象,类型为Goods //shopCar=[g1,g2,g3,null,null...] for (int i = 0; i < shopCar.length; i++) { Goods g = shopCar[i]; if(g != null){ // 这个判断商品id是否是我们要找的 if (g.id == id){ //说明是要找的商品,直接返回该商品对象 return g; } }else{ //找完了前面存在的商品,都没有找到 return null; } } return null;//代表找完了100个商品,都没有找到id一样的商品 } /** * 查询购物车中的商品对象信息,并展示出来 * */ public static void queryGoods(Goods[] shopCar) { System.out.println("===========查询购物车信息如下============"); System.out.println("编号\t\t名称\t\t\t价格\t\t购买数量"); //shopCar=[g1,g2,g3,null,null...] for (int i = 0; i < shopCar.length; i++) { // shopCar[i]代表取到商品,取到的是商品地址。 // 每个商品对象类型是Goods,故定义Goods变量来接当前遍历到的商品对象 接的也是地址,指向 Goods g = shopCar[i]; if (g != null){ //展示这个商品对象 System.out.println(g.id+"\t\t"+g.name+"\t\t\t"+g.price+"\t\t"+g.buyNumber); }else{ //无商品信息,遍历结束 break; } } } /** * 商品添加到购物车 * */ public static void addGoods(Goods[] shopCar,Scanner sc) { // 1.录入用户输入的购买商品的信息 System.out.println("请输入购买商品的编号(不重复):"); int id = sc.nextInt(); System.out.println("请输入购买商品的名称:"); String name = sc.next(); System.out.println("请输入购买商品的数量:"); int buyNumber = sc.nextInt(); System.out.println("请输入购买商品的价格:"); double price = sc.nextDouble(); // 2.把这个购买商品的信息封装成一个商品对象 Goods g = new Goods(); g.id = id; g.name = name; g.buyNumber = buyNumber; g.price = price; // 3.把这个商品对象添加到购物车数组中去 // shopCar = [null,null....] // 加商品对象是要加到为null的位置去,不能直接从1就开始加入,这样会覆盖原本的位置上存在的商品信息 for (int i = 0; i < shopCar.length; i++) { if(shopCar[i] == null){ //说明这个位置没有元素存入,那么把我们新买的商品添加到这里 shopCar[i] = g; break; //结束,因为商品已经成功存入了,不需要再继续找位置了 } } System.out.println("您的商品:"+g.name+"添加到购物车完成!"); } }
-
10.常用API(String 和 ArrayList)
- API(应用程序编程接口)的定义
- Java写好的技术(功能代码),咱们可以直接调用。
- Oracle也为Java提供的这些功能代码提供了相应的 API文档(技术使用说明书)。
- String简单介绍
- String类定义的变量可以用于存储字符串,同时String类提供了很多操作字符串的功能,我们可以直接使用。
10.1 String
10.1.1 String类概述(理解)
-
java.lang.String 类代表字符串,String类定义的变量可以用于指向字符串对象(定义字符串变量指向字符串对象),然后操作该字符串。
-
Java程序中的所有字符串文字(例如 “abc” )都为此类的对象。
String name = "Even"; String schoolName = "霍格沃茨学院";
-
String类的特点
-
String其实常被称为不可变字符串类型,它的对象在创建后不能被更改。
-
字符串对象存在哪里?
- 以 “” 方式给出的字符串对象,在字符串常量池中存储。
-
String是不可变字符串的原因?
- String变量每次的修改其实都是产生并指向了新的字符串对象。
- 原来的字符串对象都是没有改变的,所以称不可变字符串。
-
10.1.2 String类创建对象的2种方式(掌握)
-
方式一:直接使用 “” 定义。(推荐方式)
String name = "Even";
-
方式二:通过String类的构造器创建对象。
-
有什么区别吗?(面试常考)
-
以 “” 方式给出的字符串对象,在字符串常量池中存储,而且相同内容只会在其中存储一份。
-
通过构造器 new对象,每new一次都会产生一个新对象,放在堆内存中。
-
-
字符串对象的特点
- 双引号创建的字符串对象,在字符串常量池中存储同一个。
- 通过new构造器创建的字符串对象,在堆内存中分开存储。
10.1.3 String类常见面试题(理解)
10.1.4 String类常用API-字符串内容比较(掌握)
-
结论:字符串的内存比较不适合用 “==” 比较,"=="在开发中基本数据类型比较时使用。
-
字符串的内存比较:
-
推荐使用String类提供的"equals"比较:只关心内容一样即可。
-
忽略大小写比较内容的API:一般用于比较验证码的业务逻辑。
-
-
10.1.5 String类常用API-遍历、替换、截取、分割操作(重要)
String name = "我爱你中国love";
// 1.获取字符串的长度[length]
System.out.println(name.length()); /*结果个数为: 9 */
// 2.获取某个索引位置处的字符[charAt]
char c = name.charAt(1);
System.out.println(c); /*打印结果为: 爱 */
System.out.println("---------------遍历字符串中的每个字符---------------");
for(int i = 0;i < name.length();i++){
char ch = name.charAt(i);
System.out.print(ch);
}/*上面遍历结果为:我爱你中国love */
// 3.把字符串转换成字符数组[toCharArray]
char[] chars = name.toCharArray();
for(int i = 0;i < chars.length();i++){
char ch = chars[i];
System.out.print(ch);
}/*上面遍历结果为:我爱你中国love */
// 4.开始和结束索引进行截取内容,得到新字符串(包前不包后)[substring] 【实际开发中用的多】
String name2 = "Java是最厉害的编程语言!";
String rs = name2.substring(0,9);
System.out.println(rs); /*打印结果为:Java是最厉害的 */
String rs1 = name2.substring(4,9);
System.out.println(rs1); /*打印结果为:是最厉害的 */
// 5.从当前索引一直截取到末尾[substring]
String rs2 = name2.substring(4);
System.out.println(rs2); /*打印结果为:是最厉害的编程语言! */
// 6.用新值,将字符串中的旧值替换[replace]
String name3 = "这里埋葬着多比,一个自由的小精灵。我永远爱多比!";
String rs3 = name3.replace("多比","Even");
System.out.println(rs3); /*打印结果为:这里埋葬着Even,一个自由的小精灵。我永远爱Even! */
// 7.判断字符串中是否包含内容[contains]
System.out.println(name3.contains("多比")); /*打印结果为:true */
System.out.println(name3.contains("多多")); /*打印结果为:false */
// 8.判断是否以什么开始
System.out.println(name3.startsWith("这里")); /*打印结果为:true */
System.out.println(name3.startsWith("这里埋葬着多比")); /*打印结果为:true */
System.out.println(name3.startsWith("多比")); /*打印结果为:false */
// 9.按照某个内容把字符串分割成字符串数组返回
String name4 = "Harry,Hermione,Ronald";
String[] names = name4.split(",");
for(int i = 0;i < names.length();i++){
System.out.println("选择了:"+names[i]);
}/*上面遍历结果为:
选择了:Harry
选择了:Hermione
选择了:Ronald
*/
10.1.6 String类案例实战
10.2 ArrayList
10.2.1 集合概述
- 集合是与数组类似,也是一种容器,用于装数据的。
- 数组特点
- 数组定义完成并启动后,类型确定、长度固定。
- 出现问题:在个数不能确定,且要进行增删数据操作的时候,数组是不太合适的。
- 集合特点
- 集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。
- 集合非常适合做元素个数不确定,且要进行增删操作的业务场景。
- 集合提供了许多丰富、好用的功能,而数组的功能很单一
- 总结
- 数组和集合的元素存储的个数问题?
- 数组定义后类型确定,长度固定。
- 集合类型可以不固定,大小是可变的。
- 数组和集合适合的场景
- 数组适合做数据个数和类型确定的场景。
- 集合适合做数据个数不确定,且要做增删元素的场景。
- 数组和集合的元素存储的个数问题?
10.2.2 ArrayList集合快速入门
-
ArrayList集合
- ArrayList是集合中的一种,它支持索引。(暂时先学习这个,后期学习整个集合体系)
-
ArrayList集合的对象获取
-
ArrayList集合添加元素的方法
-
创建ArrayList对象,代表集合容器,往里面添加元素。
// 1.创建ArrayList集合的对象 ArrayList list = new ArrayList(); // 2.添加数据 list.add("Java"); list.add("Java"); list.add("MySQL"); list.add(23); list.add(23.5); list.add(false); list.add('中'); System.out.println(list.add('中')); /* 返回结果为:true 表示添加成功,一般不会这么操作 */ System.out.println(list); /* 打印结果为:[Java,Java,MySQL,23,23.5,false,中] */ // 3.给指定索引位置插入元素 list.add(1,"Even"); System.out.println(list); /* 打印结果为:[Java,Even,Java,MySQL,23,23.5,false,中] */
10.2.3 ArrayList对于泛型的支持
- 泛型概述
- ArrayList:其实就是一个泛型类,可以在编译阶段约束集合对象只能操作某种数据类型。
- 举例:
- ArrayList<String>:此集合只能操作字符串类型的元素。
- ArrayList<Integer>:此集合只能操作整数类型的元素。
- ==注意:集合中只能存储引用类型,不支持基本数据类型。==即:ArrayList是不对的,应该是ArrayList
//不设置泛型,相当于所有类型都可以往里面存储
ArrayList list = new ArrayList();
list.add("Java");
list.add("Java");
list.add("MySQL");
list.add(23);
list.add(23.5);
list.add(false);
list.add('中');
// ArrayList<String> list1 = new ArrayList<String>();
// 从JDK1.7开始,泛型后面的类型申明可以不写
ArrayList<String> list1 = new ArrayList<>();//表示只有String类型的才能进来
list1.add("Java");
list1.add("MySQL");
// list1.add(23); 这个就不行
- 总结:
- 怎么取统一ArrayList集合操作的元素类型?
- 使用泛型:<数据类型>
- ArrayList list1 = new ArrayList();
- 注意一点:不是所有类都支持泛型的
- 怎么取统一ArrayList集合操作的元素类型?
10.2.4 ArrayList常用API、遍历
-
ArrayList集合常用方法
ArrayList<String> list = new ArrayList<>(); list.add("Java"); list.add("Java"); list.add("MySQL"); list.add("MyBatis"); list.add("HTML"); // 1.获取某个索引位置处的元素值[get] String e = list.get(3); System.out.println(e); /* 打印结果为:MyBatis */ // 2.获取集合的大小(元素个数)[size] System.out.println(list.size());/* 打印结果为:5 */ // 3.完成集合的遍历 System.out.println(list.get(0)); System.out.println(list.get(1)); System.out.println(list.get(2)); System.out.println(list.get(3)); System.out.println(list.get(4)); /* 打印结果为: Java Java MySQL MyBatis HTML */ //改进:采用循环 for(int i = 0;i < list.size();i++){ System.out.println(list.get(i)); } /*打印结果如上*/ // 4.删除某个索引位置处的元素值,并返回被删除的元素值 [remove] System.out.println(list); /*打印结果为:[Java,Java,MySQL,MyBatis,HTML]*/ String e2 = list.remove(2); //把MySQL删除,它会返回给我们 System.out.println(e2); /* 打印结果为:MySQL */ System.out.println(list); /*打印结果为:[Java,Java,MyBatis,HTML]*/ // 5.直接删除元素值,删除成功返回true , 删除失败返回false System.out.println(list.remove("MyBatis")); /*打印结果为:true */ System.out.println(list); /*打印结果为:[Java,Java,HTML]*/ //存在两个相同元素,默认删除第一次出现的这个元素值,后面的不删除 System.out.println(list.remove("Java")); /*打印结果为:true */ System.out.println(list); /*打印结果为:[Java,HTML]*/ // 6.修改某个索引位置处的元素值 String e3 = list.set(0,"Even"); System.out.println(e3); /* 打印结果为:Even */ System.out.println(list); /*打印结果为:[Even,HTML]*/
10.2.5 ArrayList集合案例:遍历并删除元素
- 总结:
- 从集合后面遍历然后删除,可以避免漏掉元素。
10.2.6 ArrayList集合案例:存储自定义类型
-
电影类 Movie.java:
-
结论:
-
集合中存储的元素并不是对象本身,而是对象的地址。
-
10.2.7 ArrayList集合案例:元素搜索
- 学生类: