JAVA运算符与循环结构
java标识符
day2
- 标识符
- 凡是自己可以起名字的地方都叫标识符
- 比如:类名、变量名、方法名、接口名、包名
- 凡是自己可以起名字的地方都叫标识符
- 标识符的命名规则(如果不遵守,则编译不通过)
- 由26个英文字母大小写,
0-9
,_
或$
组成 - 数字不可以开头
- 不可以使用关键字和保留字,但能包含关键字和保留字
- java中严格区分大小写,长度无限制
- 标识符不能包含空格
- 由26个英文字母大小写,
- java中的名称命名规范(建议遵守)
- 包名:多单词组成时所有字母都小写:
xxxyyyzzz
- 类名、接口名:多单词组成时,所有单词的首字母大写:
XxxYyyZzz
- 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个首字母大写:
xxxYyyZzz
- 常量名:所有字母都大写,多单词时每个单词用下划线链接:
XXX_YYY_ZZZ
- 包名:多单词组成时所有字母都小写:
- 其他
- 在起名字时,为了提高阅读性,要尽量有意义,“见名知意”
- java采用unicode字符集,所以标识符可以使用汉字,但非常不建议这样做
变量的使用
- java定义变量的格式:
据类型 变量名 = 变量值;
- 说明
- 变量必须先声明,后使用
- 变量都定义在其作用域内。在作用域内,他是有效的。换句话说,除了作用域,就失效了
- 同一作用域内,不可以声明两个同名的变量
Java定义的数据类型
-
变量按照数据类型来分:
- 基本数据类型
- 整型:byte \ short \ int \ long
- 浮点型:float \ double
- 字符型:char
- 布尔型:boolean
- 引用数据类型:
- 类(class)
- 接口(interface)
- 数组(array)
- 基本数据类型
-
变量在类中声明的位置:
- 成员变量
- 局部变量
详细的:
- 整型:byte(1字节=8bit) \ short(2字节) \ int(4字节) \ long(8字节)
- byte范围:-128 ~ 127
- 若超过byte的范围,编译不通过
- 声明long型变量,必须以
l
或L
结尾 - 通常定义整型变量时,使用int型
- 整型的常量,一般是int
- byte范围:-128 ~ 127
- 浮点型:单精度float(4字节) \ 双精度double(8字节)
- 浮点型,表示带小数点的数值
- float表示数值的范围比long还大(因为他可以扩展大小)
- 定义float类型变量时,变量要以
f
或F
结尾 - 通常,定义浮点型变量,使用double型
- 浮点型常量,默认为double
- 字符型:char(1字符[即2字节])
-
定义char型变量,通常使用一对
''
,内部只能写一个字母-
也可以不带
''
char c2 = 97;//开发中非常少见 //注意5和'5'不一样
-
-
表示方式:
- 声明一个字符
- 转义字符
-
直接使用 Unicode 值来表示字符型变量
-
- 布尔型:boolean
- 只能取两个值之一:true、false
- 常常在条件判断、循环结构中使用
- 默认初始化的值是flase
基本数据类型之间的运算规则
自动类型转换
前提:这里讨论只是7种基本数据类型变量间的运算。不包含boolean类型
- 当容量小的数据类型的变量语容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型
- 说明:此时容量的大小指的是表示数的范围大和小,例如float的容量要比long的容量大,则使用float来进行数的计算
- byte、char、short --> int --> float --> double
- 特別的:当byte、char、short三种类型的变量做运算时,结果为int型,所以要使用大容量的类型进行接收
强制类型转换
- 强制类型转换:自动类型提升运算的逆运算
- 需要使用强制转换符:
(类型)变量名
- 注意点:强制类型转换,可能导致精度损失
- 需要使用强制转换符:
// 精度损失的情况
// 截断操作;强制转换int型,可以看到小数点直接没了,这种情况叫做损失精度
int i1 = (int)d1;
System.out.println(i1);
// 没有精度损失的情况
// 由于long型的l1前面都是0,所以short在截断操作的时候并没有将有效数据123给砍掉
long l1 = 123;
short s2 = (short)l1;
System.out.println(s2);
// 精度损失的情况
// 这里涉及到二进制的反码补码问题,详细说明看: https://blog.csdn.net/zy986718042/article/details/71699079
int i2 = 128;
byte b = (byte)i2;
System.out.println(b);// -128
类型不同变量类型的使用
- 编码情况
- 如果右边的常量为
long
则需要添加l或L
,否则一般情况会将其视为int
型 - 如果右边的常量为
float
则需要添加f或F
,否则一般情况会将其视为double
型
- 如果右边的常量为
- 编码情况
-
当变量与常量进行计算的时候,会将
1
这类视为int型常量
,则byte, char, short与int型常量进行计算的时候会自动提升为int型 -
当变量与常量进行计算的时候,会将
12.3
这类视为double型常量
,则其他类型与double型进行计算的时候会自动提升为double型// 1. 编码情况 // 默认情况右边的值末尾应该有l或L,但这里右边的值看做int型,自动类型提升赋值给了long型 long l = 123213; System.out.println(l); // 编译失败:右边的值没有加l或L,所以java将其看做int // 但这里的数超出了int的范围,所以发出报错 // long l1 = 2112313123123123; // 这里加了L使得右边的数为long型则可以进行赋值操作 long l1 = 2112313123123123L; // 编译失败:右边的值没有加f或F,所以java将其看做double型 // double型赋值给float型,自动类型提升所以会发生报错 // float f1 = 13.4; // ------------------------ // 2. 编码情况 // 整型常量,默认类型为int型 // 编译失败:1为常量(整型) byte b =12; // byte b2 = b + 1; // 浮点型常量,默认为double型 // 编译失败:12.3为常量(double型) // float f2 = b + 12.3;
-
字符串类型:String
-
String类型变量的使用
- String属于引用数据类型,翻译为:字符串
- 声明String类型变量时,使用一对
""
- String可以和8种基本数据变量做运算,且运算只能时连接运算:
+
- 运算的结果仍然是String类型
-
关于
+
运算符-
当
char byte short int float double
在使用+
的时候,它就代表加法计算运算符char c = 'a'; int num = 10; String str = "hello"; System.out.println(c + num + str);//107hello System.out.println(c + str + num);//ahello10 System.out.println(c + (num + str));//a10hello System.out.println((c + num) + str);//107hello System.out.println(str + num + c);//hello10a
-
当出现数字与
String
计算的时候,就是连接运算符,只做拼接运算System.out.println("* *");//* * // 不成功是因为char型和char型(int+int)会自动转换为int型,所以这里+是加法计算 System.out.println('*' + '\t' + '*');//93 // 中间是String,所以做了连接运算,int+String+int System.out.println('*' + "\t" + '*');//* * // 不成功是因为'*'+'\t'先计算,还是使用了+加法计算符 System.out.println('*' + '\t' + "*");//51* // 在最后的计算中是String+(int+String),所以做了链接运算 System.out.println('*' + ('\t' + "*"));//* *
-
练习1
// 这里的4是int常量,注意不能直接赋值给String!!!
String str1 = 4;//判断对错:false *难点!
String str2 = 3.5f + "";//判断对错:true
System.out.println(3+4+"Hello!");//输出:7Hello!
System.out.println("Hello!"+3+4);//输出:Hello!34
System.out.println('a'+1+"Hello!");//输出:98Hello!
System.out.println("Hello"+'a'+1);//输出:Hello!a1
练习2
short s = 5;
// 判断:false 因为s-2是int,但s是short,所以会报错
s = s-2;
byte b = 3;
// 判断:false 因为b+4是int,但b是byte,所以会报错
b = b + 4;
// 判断:true (int)7强制为(byte)7
b = (byte)(b+4);
char c = 'a';
int i = 5;
float d = .314F;
// 判断: true char+int=int,int+float=double;所以结果为(double)102.314...
double result = c+i+d;
byte b = 5;
short s = 3;
// 判断:false byte+short=int,所以t会报错
short t = s + b;
关于进制
- 所有数字在计算机底层都以二进制形式存在
- 对于整数,有四种表示方法:
- 二进制(binary):0,1 满2进1,以
0b
或0B
开头 - 十进制(decimal):0-9 满10进1
- 八进制(octal):0-7 满8进1,以数字0开头表示
- 十六进制(hex):0-9及A-F,满16进1,以
0x
或0X
开头表示,此处的A-F不区分大小写,如0x21AF + 1 = 0X21B0
- 二进制(binary):0,1 满2进1,以
int num1 = 0b110;
int num2 = 110;
// 注意这里不能写0128,因为八进制的八为10不存在8
int num3 = 0127;
int num4 = 0x110A;
System.out.println("num1 = " + num1);//6
System.out.println("num1 = " + num2);//110
System.out.println("num1 = " + num3);//87
System.out.println("num1 = " + num4);//4362
二进制
-
二进制的整数有如下三种形式:
- 原码:直接将一个数值换成二进制数,最高位是符号位
- 负数的反码:是对原码按位取反,只是最高位(符号位)确定为1
- 负数的补码:其反码加1
-
计算机底层都以二进制补码的形式来存储数据
- 正数的原码、反码、补码都相同
- 负数的补码是其反码+1
-
从原码到补码
- 原码
- 反码(除符号位外,取反)
- 补码(+1)
-
在二进制的符号位中,0为正数,1为负数
- 在计算机的底层中以补码存储
- -127:1000001
- -128:1000000
- 在计算机的底层中以补码存储
考察
- 标识符的命名规则有那些?(不遵循,编译不通过
- 由26个英文字母大小写,
0-9
,_
或$
组成 - 数字不可以开头
- 不可以使用关键字和保留字,但能包含关键字和保留字
- java中严格区分大小写,长度无限制
- 标识符不能包含空格
- 由26个英文字母大小写,
- 标识符的命名规范有哪些?(不遵循,编译允许都可以通过
- 包名:xxxyyyzzz
- 类名、接口名:XxxYyyZzz
- 变量名、方法名:xxxYyyZzz
- 常量名:XXX_YYY_ZZZ
- Java变量技照数据类型怎么划分?并指出Java的基本数据类型有哪8种,并指出各自占用的内存空间大小
- byte short int long
- char(一个字符=两个字节)
- float double
- boolean
- 引用数据类型:类、接口、数组
- 说明基本数据类型变量之间自动类型提升的运算规则
- byte short char -> int -> long -> float -> double
- 说明基本数据类型变量之间强制类型转换的使用规则和强转可能出现的问题
- 容量大 -> 容量小
- 使用强转符
()
- 强转可能会出现精度损失的问题
运算符
day3
- 算术运算符
- 赋值运算符
- 比较运算符(关系运算符)
- 逻辑运算符
- 位运算符
- 三元运算符
算术运算符
除号
/
除号
/*
运算符之一:算术运算符
- `+ - + - * / (前)++ (后)++ (前)-- (后)-- +`
*/
int num1 = 12;
int num2 = 5;
// 由于两个运算的变量都是int型,所以运算的结果是int型,小数点会自动去除
int result1 = num1 / num2;//2
System.out.println(result1);
int result2 = num1 / num2 * num2;//10
System.out.println(result2);
double result3 = num1 / num2;//2.0
System.out.println(result3);
// 先对int进行计算,在+0.0
double result4 = num1 / num2+0.0;//2.0
// 只要参与计算的其中一个为double,则值2.4
double result5 = num1 / (num2 + 0.0);//2.4
double result6 = (double)num1 / num2;//2.4
double result7 = (double)(num1 / num2);//2/0
System.out.println(result5);
System.out.println(result6);
System.out.println(result7);
取余运算
%
:取余运算
// 结果的符号与被摸数的符号相同
// 后面会经常使用%来判断是否能被除尽的情况
int m1 = 12;
int n1 = 5;
System.out.println("m1 % n1 = " + m1 % n1);//2
int m2 = -12;
int n2 = 5;
System.out.println("m2 % n2 = " + m2 % n2);//-2
int m3 = 12;
int n3 = -5;
System.out.println("m3 % n3 = " + m3 % n3);//2
int m4 = -12;
int n4 = -5;
System.out.println("m4 % n4 = " + m4 % n4);//-2
自增与自减
(前)++
:先自增1,再运算(后)++
:先运算,后自增1(前)--
:先自减1,再运算(后)--
:先运算,后自减1
// 注意点:
short s1 = 10;
// s1 = s1 + 1;//编译失败,因为s1是short型,不能存入int型
s1 = (short)(s1+1);//正确,类型强转
// 自增自减不会改变本身变量的数据类型
s1++;
System.out.println(s1);
// 问题:因为01111 1111+1会变成1111 1111,即-128
byte bb1 = 127;
bb1++;
System.out.println(bb1);//-128
练习1
练习2
/*
练习2
随意给出一个三位数的整数,打印显示他的个位数,十位数,百位数的值
格式如下:
数字xxx的情况如下:
个位数:
十位数:
百位数:
例如:
数字153的情况如下:
个位数:3
十位数:5
百位数:1
*/
class AriExer2 {
public static void main(String[] args){
int num = 187;
int bai = num / 100;
int shi = num % 100 / 10;//int shi = num /10 % 10
int ge = num % 10;
System.out.println("百位为:"+ bai);
System.out.println("十位为:"+ shi);
System.out.println("个位为:"+ ge);
}
}
赋值运算符
- 符号:
=
- 当
=
两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理 - 支持连续赋值
- 当
= += *= /= %=
/*
运算符之二:赋值运算符
- `= += *= /= %=`
*/
// 赋值符号:=
int i1 = 10;
int j1 = 10;
int i2, j2;
// 连续赋值
i2 = j2 = 10;
int i3 = 10, j3 = 20;
// ------------------------
int num1 = 10;
num1 +=2;//num1 = num1 + 2;
System.out.println(num1);//12
int num2 = 12;
num2 %= 5;
System.out.println(num2);
// 与自增自减那样,`+= *= /= %=`不会改变本身的数据类型
short s1 = 10;
s1 +=2;
System.out.println(s1);
// 在开发中:如果希望变量实现+2的操作,有几种方法?(前提:int num = 10)
// 推荐方法:num += 2;
// 方法二:num = num + 2;
// 在开发中:如果希望变量实现+1的操作,有几种方法?(前提:int num = 10)
// 推荐方法:num++;
// 方法二:num += 1;
// 方法三:num = num + 2;
练习
-
思考1
short s = 3; s = s+2; s += 2; // 上述代码中有什么区别
- 第2行会报错,因为s+2是int型,第3行不会报错
-
思考2
int i = 1; i *= 0.1; System.out.println(i); i++; System.out.println(i);
- 因为*=不会改变本身的数据类型,所以这里不会报错,第3行是输出0,第五行是输出1
-
思考3
int m = 2; int n = 3; n *= m++; System.out.println("m="+m); System.out.println("n="+n);
-
输出:
m=3 n=6
-
-
思考4
int n = 10; n += (n++) + (++n); System.out.println(n);
- 32
- n = n[10] + (10[n=11] + 12[n=12])
- 32
比较运算符
- 比较运算符的结果都是boolean型,也就是要么是true,要么是false
- 比较运算符
==
不能误写成=
- 结论
- 比较运算符的结果是boolean类型
- 区分
==
和=
/*
运算符之三:比较运算符
== != > < >= <= instanceof
*/
int i = 10;
int j = 20;
System.out.println(i == j);//false
// 赋值并输出
System.out.println(i = j);//20
boolean b1 = true;
boolean b2 = false;
System.out.println(b2 == b1);//fa;se
System.out.println(b2 = b1);//true
练习
- 练习1
boolean b1 = false;
// 注意区分==和=的区别
if(b1==true)
System.out.println("结果为真");//=输出这个
else
System.out.println("结果为假");//==输出这个
逻辑运算符
- 结论:
- 逻辑运算符操作的都是boolean类型的变量
- 区分:& 与 &&
- 相同点1: & 与 && 的运算结果相同
- 相同点2: 当符号左边是true时,二者都会执行符号右边的运算
- 不同点:当符号左边是false时,&继续执行符号右边的运算。&&不再执行符号右边的运算
- 开发中推荐使用&&
- &&和&结果一样,&&有短路效果,左边为false,右边不执行;&左边无论是什么,右边都会执行。
- 区分:| 与 ||
- 相同点1: | 与 || 的运算结果相同
- 相同点2: 当符号左边是false时,二者都会执行符号右边的运算
- 不同点3:当符号左边是true时,|继续执行符号右边的运算。||不再执行符号右边的运算
- 开发中推荐使用||
- ||和|结果一样,||有短路效果,左边为true,右边不执行;|左边无论是什么,右边都会执行。
boolean b1 = true;
b1 = false;
int num1 = 10;
if(b1 & (num1++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num1="+num1);
boolean b2 = true;
b2 = false;
int num2 = 10;
if(b2 && (num2++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num2="+num2);
// 区分:| 与 ||
// 相同点1: | 与 || 的运算结果相同
// 相同点2: 当符号左边是false时,二者都会执行符号右边的运算
// 不同点3:当符号左边是true时,|继续执行符号右边的运算。||不再执行符号右边的运算
// 开发中推荐使用||
boolean b3 = false;
b3 = true;
int num3 = 10;
if(b3 | (num3++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num3="+num3);
boolean b4 = false;
b4 = true;
int num4 = 10;
if(b4 || (num4++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num4="+num4);
练习
- 练习1
int x = 1; int y = 1; //flase & true = false if(x++==2 & ++y==2){ x=7; } x=2,y=2 System.out.println("x="+x+",y="+y);
- 练习2
int x=1, y=1; //false if(x++==2 && ++y==2){ x=7; } //x=2.y=1; 由于双&&,所以false后面不执行 System.out.println("x="+x+",y="+y);
- 练习3
int x=1, y=1; //true | false = true if(x++==1 | ++y==1){ x=7; } //x=7,y=2 System.out.println("x="+x+",y="+y);
- 练习4
int x=1,y=1; //true if(x++==1 || ++y==1){ x=7; } //x=7,y=1; 由于双||,所以true后面不执行 System.out.prinln("x="+x+",y="+y);
- 练习5
class Test{ public static void main(String[] args){ boolean x=true; boolean y=false; short z=42; //if(y==ture) // z++==42为true,y=true为true if((z++==42)&&(y=true))z++; // x=false为false,++z==45为true if((x=false) || (++z==45))z++; System.out.println("z="+z); }//z=46 }
位运算符
-
<< >> >>>& | ^ ~
-
结论:
- 位运算符操作的都是整型的数据
<<
:在一定范围内,每向左移一位,相当于 *2>>
:在一定范围内,每向右移一位,相当于 /2
-
面试题:最高效方式的计算2*8:2<<3,或8<<1
-
<<
表示左移移,不分正负数,低位补0- 3: 0011 | 3<<2: 1100,即3<<2=12
- 或
3*2*2=12
- 结论:每移一位,都乘以一次2
- 或
正数:r = 20 << 2 20的二进制补码:0001 0100 向左移动两位后:0101 0000 结果:r = 80 负数:r = -20 << 2 -20 的二进制原码 :1001 0100 -20 的二进制反码 :1110 1011 -20 的二进制补码 :1110 1100 左移两位后的补码:1011 0000 反码:1010 1111 原码:1101 0000 结果:r = -80
- 3: 0011 | 3<<2: 1100,即3<<2=12
-
>>
表示右移,如果该数为正,则高位补0,若为负数,则高位补1;- 注:以下数据类型默认为byte-8位
正数:r = 20 >> 2 20的二进制补码:0001 0100 向右移动两位后:0000 0101 结果:r = 5 负数:r = -20 >> 2 -20 的二进制原码 :1001 0100 -20 的二进制反码 :1110 1011 -20 的二进制补码 :1110 1100 右移两位后的补码:1111 1011 反码:1111 1010 原码:1000 0101 结果:r = -5
-
>>>
表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0正数: r = 20 >>> 2 的结果与 r = 20 >> 2 相同; 负数: r = -20 >>> 2 注:以下数据类型默认为int 32位 -20:源码:10000000 00000000 00000000 00010100 反码:11111111 11111111 11111111 11101011 补码:11111111 11111111 11111111 11101100 右移:00111111 11111111 11111111 11111011 结果:r = 1073741819
-
&|^
-
代码
int m = 12; int n = 5; System.out.println("m & n: " + (m & n)); System.out.println("m | n: " + (m | n)); System.out.println("m ^ n: " + (m ^ n)); /* m & n: 4 m | n: 13 m ^ n: 9 */
-
二进制的运算
-
m = k^n = (m^n)^n
-
int i = 21;
System.out.println("i << 2: " + (i << 2));
System.out.println("i << 3: " + (i << 3));
System.out.println("i << 27: " + (i << 27));
i = -21;
System.out.println("i << 27: " + (i << 27));
int m = 12;
int n = 5;
System.out.println("m & n: " + (m & n));
System.out.println("m | n: " + (m | n));
System.out.println("m ^ n: " + (m ^ n));
// 练习:交换两个变量的值
int num1 = 10;
int num2 = 20;
System.out.println("num1 = " + num1 + ",num2 = " + num2);
// 方法一:定义临时变量的方法(推荐的方法)
int temp = num1;
num1 = num2;
num2 = temp;
System.out.println("num1 = " + num1 + ",num2 = " + num2);
// 方法二:好处:不用定义零食变量
// 弊端:
// 1. 相加操作可能会超出存储范围
// 2. 有局限性,只能适用于数值类型
num1 = num1 + num2;
num2 = num1 - num2;
num1 = num1 - num2;
System.out.println("num1 = " + num1 + ",num2 = " + num2);
// 方法三:使用位运算符
// 有局限性,只能适用于数值类型
num1 = (num1 ^ num2);
num2 = num1 ^ num2;
num1 = num1 ^ num2;
System.out.println("num1 = " + num1 + ",num2 = " + num2);
三元运算符
- 结构:(条件表达式)?表达式1: 表达式2
- 说明
- 条件表达式的结果为boolean类型
- 根据条件表达式真或假,决定执行表达式1,还是表达式2
- 如果表达式为true,则执行表达式1
- 如果表达式为false,则执行表达式2
- 表达式1和表达式2要求使用的类型是一致的
- 三元运算符可以嵌套使用
- 嵌套使用的前提:编写的效率很高,算法改良
- 凡是可以使用三元运算符的地方,都可以改写成if-else
- 三元运算符与if-else的练习与区别
- 三元运算符可以简化if-else语句
- 三元运算符要求必须返回一个结果
- if后的代码可有多个语句
- 反之,不成立,因为if可以嵌套很多个elseif,是可以做复杂的流程语句的,三元运算符只建议用在简单的条件运算符
- 三元运算符与if-else的练习与区别
- 如果程序既可以使用三元运算符,又可以if-else结构,那么优先选择三元运算符。
- 原因:简洁、执行效率高
// 获取两个整数的较大值
int m = 12;
int n = 5;
int max = (m > n) ? m : n;
System.out.println(max);
// 编译错误:int型和字符串型
// (m > n) ? 2 :"大";
//-----------------------
// 嵌套写法虽然简单,但不建议写,因为可读性很差
String maxStr = (m > n)? "m大" : ((m == n)? "m和n相等" : "n大");
System.out.println(maxStr);
//-----------------------
// 获取三个数的最大值
int n1 = 12;
int n2 = 30;
int n3 = -43;
int max1 = (n1 > n2)? n1 : n2;
int max2 = (max1 > n3)? max : n3;
System.out.println("三个数中的最大值为:" + max2);
// 改写成if-else
if(m > n){
System.out.println(m);
}else{
System.out.println(n);
}
运算符的优先级
- 运算符有不同的优先级,所谓优先级就是表达式运算中的运算优先顺序如下图越往上优先级越高
- 只有弹幕运算符、三元运算符、赋值运算符是从右向左运算的
考察
&
和&&
的异同
- 相同点1: & 与 && 的运算结果相同
- 相同点2: 当符号左边是true时,二者都会执行符号右边的运算
- 不同点:当符号左边是false时,&继续执行符号右边的运算。&&不再执行符号右边的运算
- 开发中推荐使用&&
- &&和&结果一样,&&有短路效果,左边为false,右边不执行;&左边无论是什么,右边都会执行。
-
程序输出
class OperatorTest{ public static void main(String[] args) { boolean x = true; boolean y = false; short z = 40; if ((z++ == 40) && (y = true)){ z++; } if ((x = false) || (++z == 43)){ z++; } System.out.println("z= "+z); } }
- 结果为:z= 44
- 第一个if中,z++==40和y=true都是true,true&&true所以执行第一个if语句
- 第二个if中,x=false是false,++z==43是true,false||true=true所以执行第二个if语句
- 结果为:z= 44
-
定义三个int型变量并赋值,使用三元运算符或者if-else活的这三个数中较大数的实现
int num1 = 10; int num2 = 21; int num3 = -21; int max; if(num1 >= num2 && num1 >= num3){ max = num1; }else if(num2 >= num1 && num2 >= num3){ max = num2; }else{ max = num3; } System.out.println("三个数的最大值为:" + max);
-
编写程序,声明2个double型变量并赋值,判断第一个数大于10.0,且第2个数小于20.0,打印两数之和。否则,打印两数的乘积
double d1 = 12.3; double d2 = 32.1; if((x > 10.0) && (y<20.0)){ System.out.println("两数之和:" + (x+y)); }else{ System.out.println("两数乘积:" + (x*y)); }
-
交换两个变量值得代码的实现
String s1 = "北京"; String s2 = "南京"; String temp = s1; s1 = s2; s2 = temp
程序流程控制
- 流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块
- 其流程控制方式采用结构化程序设计中规定的三种基本流程结构
- 顺序结构
- 程序从上到下逐行的执行,中间没有任何判断和跳转
- 分支结构
- 根据条件,选择性的执行某段代码
- 有if...else和switch-case两种分支语句
- 循环结构
- 根据循环条件,重复性的执行某段代码
- 有while、do...while、for三种循环语句
- 注:JDK1.5提供了foreach循环,方便的便利集合、数组元素
- 顺序结构
if-else结构 - 分支语句1
- if语句三种格式
-
条件执行
if(条件表想达式){ 执行代码块; }
-
二选一
if(条件表达式){ 执行代码块1; }else{ 执行代码块2 }
-
n选一
if(条件表达式1){ 执行代码块1; }else if(条件表达式2){ 执行代码块2; } //······ else{ 执行代码块n; }
-
// example1
int hearBeats =79;
if(hearBeats < 60 || hearBeats > 100){
System.out.println("需要做进一步检查");
}
System.out.println("检查结束");
// example2
int age = 23;
if(age < 18){
System.out.println("未成年");
}else{
System.out.println("已成年");
}
// example3
if(age < 0){
System.out.println("输入数据错误");
}else if(age < 18){
System.out.println("青少年时期");
}else if(age < 35){
System.out.println("青壮年时期");
}else if(age < 60){
System.out.println("中年时期");
}else if(age<120){
System.out.println("老年时期");
}else{
System.out.println("成仙咯!");
}
Scanner 输入
-
为了更好的为后面铺垫,这里从开始使用输入开始记
-
如何从键盘获取不同类型的变量:需要使用Scanner类
-
实现步骤
- 导包:import java.util.Scanner;
- Scanner的实例化:Scanner scan = new Scanner(System.in);
- 调用Scanner类的相关方法(next()/nextXxx()),来获取指定类型的变量
- 注意:需要根据相应的方法,来输入指定类型的值。如果输入的数据类型与要求的类型不匹配时,会报出异常:InputMisMatchException导致程序终止
//1.导包
import java.util.Scanner;
class ScannerTest {
public static void main(String[] args) {
//2.Scanner的实例化
Scanner scan = new Scanner(System.in);
//3. 调用Scanner类的相关方法
System.out.println("请输入姓名:");
String name = scan.next();
System.out.println(name);
System.out.println("请输入年龄:");
int age = scan.nextInt();
System.out.println(age);
System.out.println("请输入体重:");
double weight = scan.nextDouble();
System.out.println(weight);
System.out.println("是否单身?(true/false)");
boolean islonely = scan.nextBoolean();
System.out.println(islonely);
// 对于char型的获取,Scanner没有提供相关的方法,只能获取一个字符串
System.out.println("请输入你的性别:(男/女)");
String gender = scan.next();
char genderChar = gender.charAt(0);//获取索引为0位置上的字符
System.out.println(genderChar);
}
}
获取char单个字符
- 对于char型的获取,Scanner没有提供相关的方法,只能获取一个字符串
- 但你可以通过
string.charAt(pos)
来获取pos位置的字符
System.out.println("请输入你的性别:(男/女)");
String gender = scan.next();
char genderChar = gender.charAt(0);//获取索引为0位置上的字符
System.out.println(genderChar);
小练习
题目1
小米参加java考试,他和父亲大米达成承诺:
如果:成绩为100分,奖励一台BMW
成绩为(80, 99]时,奖励一台iphone xs max
成绩为[60, 80]时,奖励一个ipad
其他时,什么奖励也没有
请从键盘输入小米的期末成绩,并加以判断
-
分析说明
- else结构是可选的
- 正对于条件表达式:
- 如果多个条件表达式之间是"互斥"关系(或没有交集的关系),那个判断和执行语句声明在上面还是下面,无所谓
- 如果多个条件表达式之间有交集的关系,需要根据实际情况,考虑清楚应该将哪个结构声明在上面
- 如果多个条件表达式之间有包含的关系,通常情况下,需要将范围小的声明在范围大的范围上面。否则,范围小的将不会被执行
import java.util.Scanner;
class IfTest1 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入小米的期末成绩:(0-100)");
int score = scan.nextInt();
// 在这里你也可以将&&后面的条件去掉,也是一样的作业
if(score == 100){
System.out.println("奖励一辆BMW");
}else if(score > 80 && score <= 99){
System.out.println("奖励一台iphone xs max");
}else if(score >= 60 && score <= 80){
System.out.println("奖励一个ipad");
}else{
System.out.println("什么奖励也没有");
}
}
}
题目2
编写程序:由键盘输入三个整数分别存入变量num1、num2、num3,对他们进行排序(使用 if-else if-else),并且从小到大输出
- 说明
- if-else结构是可以相互嵌套的
- 如果if-else结构中的执行语句只有一行时,对于的一对{}可以省略。但不建议省略,因为容易出现观察的错误
import java.util.Scanner;
class IfTest2{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入第一个整数");
int num1 = scanner.nextInt();
System.out.println("请输入第二个整数");
int num2 = scanner.nextInt();
System.out.println("请输入第三个整数");
int num3 = scanner.nextInt();
if(num1 >= num2){
if(num3 >= num1){
System.out.println(num2 + "," + num1 + "," + num3);
}else if(num3 <= num2){
System.out.println(num3 + "," + num2 + "," + num1);
}else{
System.out.println(num2 + "," + num3 + "," + num1);
}
}else{
if(num3 >= num2){
System.out.println(num1 + "," + num2 + "," + num3);
}else if(num3 <= num1){
System.out.println(num3 + "," + num1 + "," + num2);
}else{
System.out.println(num1 + "," + num3 + "," + num2);
}
}
}
}
if语句练习1
//下列代码,若有输出,指出输出结果
int x = 4;
int y = 1;
if (x>2){
if ( y>2)
System.out.println(x + y);
System.out.println("atguigu");
}else
System.out.println("x is " + x);
// 这里是输出atguigu,因为进入了第一个if,如何里面的if不符合不执行就继续执行下面的语句,下面的else是对应第一个if的
//上面的变形
int x = 4;
int y = 1;
if (x>2)
if ( y>2)
System.out.println(x + y);
// System.out.println("atguigu");
else // 就近原则,默认匹配上门的if
System.out.println("x is " + x);
// x is 4
if练习语句2
狗狗年龄计算器,狗前两年的寿命相当于人一年,狗10.5岁,之后每一年就是增加4岁,那5岁的狗就是10.5+10.5+4+4+4=33岁,请写出狗狗计算器
if练习语句3
-
这里主要是要学会获取一个随机数,具体使用函数
Math.random()
Math.random()
获取的是0.0-1.0
的double型数字,即[0.0, 1.0]
-
获取a-b之间随机值的公式:
(int)(Math.random() * (b - a + 1) + a)
if练习语句4
- 给出三个条件,高180cm以上,富一千万以上,帅true
- 满足三个条件则:
一定要嫁给他
- 三个条件中有真的情况则:
嫁吧,比上不足,比下有余
- 如果三个条件都不满足则:
不嫁
- 满足三个条件则:
- 这里第三个条件,输入字符串的值判断语句
String.equals("判断的字符串");
import java.util.Scanner;
class IfExer2{
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入升高:(cm)");
int height = scan.nextInt();
System.out.println("请输入你的财富:(千万)");
double wealth = scan.nextDouble();
/*方式一,判断布尔值
System.out.println("请输入是否帅:(true/false)");
boolean isHandsome = scan.nextBoolean();
if(height>=180 && wealth >= 1 && isHandsome){
System.out.println("一定要嫁给他");
}else if(height>=180 || wealth >= 1 || isHandsome){
System.out.println("嫁吧,比上不足,比下有余");
}else{
System.out.println("不嫁");
}
*/
// 方式二,判断字符串
System.out.println("请输入是否帅:(是/否)");
String isHandsome = scan.next();
if(height>=180 && wealth >= 1 && isHandsome.equals("是")){
System.out.println("一定要嫁给他");
}else if(height>=180 || wealth >= 1 || isHandsome.equals("是")){
System.out.println("嫁吧,比上不足,比下有余");
}else{
System.out.println("不嫁");
}
}
}
switch-case结构 - 分支语句2
格式
Switch(表达式){
case 常量1:
语句1;
//break;//可选的
case 常量2:
语句2;
//break;
···
default:
语句n;
//break;
}
说明
-
根据 switch 表达式中的值,依次匹配各个case中的常量,一旦匹配成功,则进入相应case结构中,调用其执行语句。当调用完执行语句后,则仍然继续向下执行其他case结构中的执行语句,直到遇到break关键字或switch-case结构末尾为止结束
-
break, 可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出switch-case结构
-
switch 结构中的表达式,只能是如下的6中数据类型之一
- byte, short, char, int, 枚举类型(JDK5.0新增), String类型(JDK7.0新增)
-
case 之后只能声明常量,不能声明一个范围
-
break 关键字是可选的
-
default: 相当于if-else中的else
- default关键字是可选的,而且位置是灵活的,你可以放在任何地方,开头或者中间,如果在开头,case都没匹配上他都会按序执行,从default到case n,但默认放末尾
- 凡是可以使用switch-case的结构,都可以转换为if-else,反之,不成立
- 再写分支结构时,当发现既可以使用switch-case(同时switch中表达式的取值不太多),又可以使用if-else时,优先选择switch-case,因为switch-case执行效率稍高
- 如果switch-case结构中的多个case的执行语句相同,则可以考虑进行合并
例题2
- 对学生成绩大于60分的,输出"合格",低于60分的,输出"不合格"
-
说明:如果switch-case结构中的多个case的执行语句相同,则可以考虑进行合并
System.out.println("请输入学生的成绩"); Scanner scan = new Scanner(System.in); int score = scan.nextInt(); int scoreout; //更优的解法 scoreout = score / 60; switch(scoreout){ case 0: System.out.println("不合格"); break; case 1: System.out.println("合格"); break; } scoreout = score / 10; //次优的解法 switch(scoreout){ case 0: case 1: case 2: case 3: case 4: case 5: System.out.println("不合格"); break; case 6: case 7: case 8: case 9: case 10: System.out.println("合格"); break; }
-
例题4
- 从键盘上输入2019的"month"和"day",要求通过程序输出输入的日期为2019的第几天
- 说明:break在switch-case是可选的
Scanner scan = new Scanner(System.in);
System.out.println("请输入2019的month:");
int month = scan.nextInt();
System.out.println("请输入2019的day:");
int day = scan.nextInt();
// 定义一个变量来保存总天数
int sumDays = 0;
// 如果使用if-else来写,就会重复12此,很冗余(多余)
switch (month){
case 12:
sumDays += 30;
case 11:
sumDays += 31;
case 10:
sumDays += 30;
case 9:
sumDays += 31;
case 8:
sumDays += 31;
case 7:
sumDays += 30;
case 6:
sumDays += 31;
case 5:
sumDays += 30;
case 4:
sumDays += 31;
case 3:
sumDays += 28;
case 2:
sumDays += 31;
case 1:
sumDays += day;
}
System.out.println("2019年" + month + "月" + day + "日是当前年的第" + sumDays + "天");
例题5
-
从键盘分别输入年、月、日,判断这一天是当年的第几天
-
这里核心在于闰年的标准
1. 可以被4整除,且不可被100整除 或 2, 可以被400整除
-
case 3:
// 判断year是否是闰年
// 可以被4整除,且不可被100整除或可以被400整除
if((year % 4==0 && year % 100 !=0) || year % 400 == 0){
sumDays += 29;
}else{
sumDays +=28;
}
循环结构
-
循环结构
- 在某些条件满足的情况下,反复执行特定代码的功能
-
循环语句分类
- for 循环
- while 循环
- do-while 循环
-
循环语句的四个组成部分
- 初始化部分(init_statement)
- 想你换条件部分(test_exp)
- 循环体部分(body_statement)
- 迭代部分(alter_statement)
for循环
for循环结构的使用
- 循环结构的四个要素
- 初始化条件
- 循环条件
- 循环条件是boolean类型
- 循环体
- 迭代条件
for循环的结构
- 其中的1234放入上述的四个要素
for(1;2;4){
3
}
-
执行过程:1 - 2 - 3 - 4 - 2 - 3 ··· - 2
-
在for循环内定义的变量,只在for循环内有效,除了for循环就失效了
练习
//练习:
int num = 1;
for(System.out.print('a');num <= 3; System.out.print('c'),num++){
System.out.print('b');
}
//输出结果:abcbcbc
//例题:遍历100以内的偶数, 输出所有偶数的和,输出偶数的个数
int sum = 0;// 记录所有偶数的和
int count = 0;// 记录偶数的个数
for(int i = 1;i <= 100; i++){
if(i % 2 == 0){
System.out.print(i + " ");
sum += i;
count++;
}
}
System.out.println();
System.out.println("总和为:" + sum);
System.out.println("个数为:" + count);
考察
day5
-
switch后面使用的表达式可以是那些数据结构
byte short char int 枚举类型 String类型
-
使用switch语句改下列if语句
int a = 3; int x = 100; if(a==1) x+=5; else if(a==2) x+=10; else if(a==3) x+=16; else x+=34;
int a = 3; int x = 100; switch(a){ case 1: x+=5; break; case 2: x+=10; break; case 3: x+=16; break; default: x+=34; }
-
谈谈你对三元运算符、if-else和switch-case结构使用场景的理解
- 三元与switch-case都可以写成if-else,反之不一定成立
- 通常使用分支选择结构都是使用if-else,但如果满足特定比如判断条件简单,或者二选一的情况那就可以选择switch-case或三元运算符
-
如何从控制台获取 String和int型的变量,并输出?使用代码实现
// 导包 import java.util.Scanner; // 实例化;变量类型 变量名 = 变量值 Scanner scan = new scan(System.in); // 获取 String info = scan.next(); // char是没有的,需要额外用其他方法实现 char info_char = info.charAt(0);//获取索引为0位置上的字符 int id = scan.nextIn();
-
使用for循环遍历100以内的奇数,并计算所有的奇数的和并输出。
int sum = 0 for(int i = 1;i <= 100; i++){ if(i % 2 != 0){ System.out.println(i); sum += i; } } System.out.println("奇数的和:" + sum);
循环的四要素
-
初始化条件
-
循环条件
- 循环条件是boolean类型
-
循环体
-
迭代条件
while 循环
while循环的使用
- 循环结构的四个要素
- 初始化条件
- 循环条件
- 循环条件是boolean类型
- 循环体
- 迭代条件
while循环的结构
1
while(2){
3;
4;
}
- 执行过程: 1 - 2 - 3 - 4 - 2 - 3 - 4 - ··· - 2
说明
- 写while循环千万不要丢了迭代条件。一旦丢了,就可能导致死循环
- 写程序要避免出现死循环(算法具有有限性)
- for循环和while循环可以相互转换的
- 区别:for循环和while循环的初始化条件部分的作用范围不同
do-while 循环
do-while的使用
- 循环结构的四个要素
- 初始化条件
- 循环条件
- 循环条件是boolean类型
- 循环体
- 迭代条件
do-while循环结构:
1
do{
3;
4;
}while(2);
- 执行过程:1 - 3 - 4 - 2 - 3 - 4 - ··· - 2
说明
- do-while循环至少会执行一次循环体
- 开发中,使用for和while更多一些,较少使用do-while
练习
- 从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为0时结束程序
说明:
1. 不在循环条件部分限制次数的结构:for(;;)或while(true)
2. 结束循环的几种方式
1. 循环条件部分返回false
2. 循环体中,执行break
*/
import java.util.Scanner;
class ForWhileTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int positiveNumber = 0;//记录正数的个数
int negativeNumber = 0;//记录负数的个数
//如果用for循环写,则按下面写即可
//for(;;)
while(true){
int number = scan.nextInt();
// 判断number的正负情况
if(number > 0){
positiveNumber++;
}else if(number < 0){
negativeNumber++;
}else{
//一旦执行break,跳出循环
break;
}
}
System.out.println("输入的正数个数为:" + positiveNumber);
System.out.println("输入的负个数为:" + negativeNumber);
/* 自己写的
int loop = 1;
int sum1 = 0;
int sum2 = 0;
while(loop != 0){
System.out.print("请输入整数:");
loop = scan.nextInt();
if (loop > 0){
sum1++;
}else if (loop < 0){
sum2++;
}else{
System.out.println("输入有误");
}
}
System.out.println("正数:" + sum1);
System.out.println("负数:" + sum2);
*/
}
}
嵌套循环
- 其内容其实就和嵌套分支一样,嵌套循环就是循环里面套循环
- 建议的嵌套层数是不超过三层,一旦超过三层则建议是否能有更好的解决方法
嵌套循环的使用
- 嵌套循环
- 将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环
- 两种嵌套循环结构
- 外层循环:循环结构B
- 内层循环:循环结构A
- 说明
- 内层循环结构遍历一遍,只相当于外层循环体执行了一次
- 假设外层循环需要执行m此,内层循环需要执行n此,此时内层循环一共执行了m*n次
- 技巧
- 外层循环控制行数,内层循环控制列数
关于质数的算法优化
-
100以内的所有质数的输出
-
质数:素数,只能被1和他本身整除的自然数。
从2开始,到这个数-1结束为止,都不能被这个数本身整除 -
算法是编程的内功核心,一个好的算法可以事半功倍,最大效益化的压榨机器的性能
-
普通的写法,没有任何的优化
class PrimeNumberTest { public static void main(String[] args) { boolean isFlag = true;//表示i是否被j除尽,一旦除尽,修改其值 for(int i = 2;i <= 100;i++){//遍历100以内的自然数 for(int j = 2;j < i;j++){//j: 被i除 if(i % j == 0){//i被j除尽则置false isFlag = false; } } if(isFlag == true){ System.out.println(i); } //重置isFlag isFlag = true; } } }
-
添加了优化
class PrimeNumberTest1 { public static void main(String[] args) { boolean isFlag = true;//表示i是否被j除尽,一旦除尽,修改其值 // 获取当前时间的毫秒数 long start = System.currentTimeMillis(); int count = 0;//记录质数的个数 for(int i = 2;i <= 100000;i++){//遍历100以内的自然数 // Math.sqrt()开方 // 优化二:对本身是质数的自然数是有效的 // for(int j = 2;j < i;j++){ for(int j = 2;j < Math.sqrt(i);j++){//j: 被i除 if(i % j == 0){//i被j除尽则置false isFlag = false; break;//优化一:只对本身非质数的自然数是有效的 } } if(isFlag == true){ // System.out.println(i); count++; } //重置isFlag isFlag = true; } // 获取当前时间的毫秒数 long end = System.currentTimeMillis(); System.out.println("质数的个数为:" + count); System.out.println("所花费的时间为:" + (end - start)); //未优化:17710 // 优化一:1546 // 优化二: 13 } }
题外 - 获取当前的时间毫秒数
与其他语言一样,java也有获取自1970年1月1日UTC以来的机器时间,
long start = System.currentTimeMillis();
System.out.println(start);//1634815711071
题外 - 求根号
Math.sqrt()
特殊流程控制语句
break、continue
-
break和continue关键字的使用
-
两者区别
关键字 使用范围 循环中使用的作用(不同点) 相同点 break switch-case, 循环结构中 结束当前循环 关键字后面不能声明执行语句 continue 循环结构中 结束单次循环 关键字后面不能声明执行语句 -
java中可以让循环添加标签,在使用break和continue的时候可以对特定的循环进行操作
break [lable];
结束指定标签标识的一层循环continue [lable];
结束指定标识的一层循环的当此循环
for(int i = 1;i <= 10;i++){
if(i % 4 == 0){
break;//123
// continue;//1235678910
// break和continue的后面不能接执行语句
// System.out.println("输出");
}
System.out.print(i);
}
System.out.println("\n");
// -------------------------
//java中可以让循环添加标签
label:for(int i = 1;i <= 4;i++){
for(int j = 1;j <= 10;j++){
if(j % 4 == 0){
// break;//默认跳出包括此关键字最近的一层循环
// continue;
// break lable;//结束指定标签标识的一层循环
continue label;//结束指定标识的一层循环的当此循环
}
System.out.print(j);
}
System.out.println();
}
return
return
:并非专门用于结束循环的,他的功能是结束一个方法,当一个方法执行到一个return语句时,这个方法将被结束- 与break和continue不同的是,return直接结束整个方法,不管这个return处于多少层循环之内
考察
-
循环结构是如何最后退出循环的,有哪些不同的情况请说明
- 循环条件返回false
- 在循环体内,一旦执行到break,跳出循环
- continue是跳过此次循环,所以不算
return是跳过方法的,所以不算专门来结束循环的
-
指出如下程序输出的结构
label:for (int i = 1; i<= 4;i++){ for (int j = 1;j <= 10;j++){ if (j % 4 == 0){ continue label; } System.out.print(j); } System.out.println(); }
- output:123123123123
-
一个数如果恰好等于它的因子之和,这个数就称为”完数“。例如 6=1+2+3. 编程找出1000以内的所有完数。(因子:除去这个数本身的其他约数)
for(int i = 1;i <= 1000;i++){ int factor = 0; for(int j = 1;j <= i/2;j++){ if(i % j == 0){ factor += j; } } if(i == factor){ System.out.println(i); } }
-
说明break和continue使用上的相同点和不同点
关键字 使用范围 循环中使用的作用(不同点) 相同点 break switch-case, 循环结构中 结束当前循环 关键字后面不能声明执行语句 continue 循环结构中 结束单次循环 关键字后面不能声明执行语句 -
从控制台输出:
/* ****** ***** **** *** ** * */ for(int i = 1; i <= 6;i++){ for(int j = 1; j <= 7 - i;j++){ System.out.print("*"); } System.out.println(); }