常量与变量
1.1 常量:在Java程序中固定不变的数据。
常量类型 | 解释 | 举例 |
---|---|---|
整数常量 | 所有的整数 | 0,1, 567, -9 |
小数常量 | 所有的小数 | 0.0, -0.1, 2.55 |
字符常量 | 单引号 引起来,只能写一个 字符,必须有内容 |
'a' , ' ', '好' |
字符串常量 | 双引号 引起来,可以写多个字符,也可以不写 |
"A" ,"Hello" ,"你好" ,"" |
布尔常量 | 只有两个值(流程控制中讲解) | true , false |
空常量 | 只有一个值(引用数据类型中讲解) | null |
注意: |
- 字符串可以为空
""
,但是字符不能为空''
。如System.out.println('');
会报错。 - 空常量不能直接用来打印输出,如
System.out.println(null);
会报错。
1.2 变量:在程序中可以变化的量称为变量。
Java中要求一个变量每次只能保存一个数据,必须要明确保存的数据类型
。
基本数据类型
2.1 Java的数据类型分为两大类:
- 基本数据类型:包括
整数
、浮点数
、字符
、布尔
。 - 引用数据类型:包括
类
、数组
、接口
。
2.2 四类八种基本数据类型:
数据类型 | 关键字 | 内存占用 | 取值范围 |
---|---|---|---|
字节型 | byte | 1个字节 | -128~127 |
短整型 | short | 2个字节 | -32768~32767 |
整型 | int(默认) | 4个字节 | -2的31次方~2的31次方-1 |
长整型 | long | 8个字节 | -2的63次方~2的63次方-1 |
单精度浮点数 | float | 4个字节 | 1.4013E-45~3.4028E+38 |
双精度浮点数 | double(默认) | 8个字节 | 4.9E-324~1.7977E+308 |
字符型 | char | 2个字节 | 0-65535 |
布尔类型 | boolean | 1个字节 | true,false |
- Java中的默认类型:整数类型是
int
、浮点类型是double
。 - 整数型
byte short int long
。
2.3 变量定义
变量定义的格式包括三个要素:数据类型、变量名、数据值。
数据类型 变量名 = 数据值;
long类型:建议数据后加L表示。
float类型:建议数据后加F表示。
- 变量名称:在同一个大括号范围内,变量的名字不可以相同。
- 变量赋值:定义的变量,不赋值不能使用。
2.4 引用数据类型(今后学习)
字符串、数组、类、接口、Lambda
注意事项:
- 字符串不是基本类型,而是
引用类型
。 - 浮点型可能只是一个
近似值
,并非精确的值。 - 数据范围与字节数不一定相关,例如float数据范围比long更加广泛,但是float是4字节,long是8字节。
- 浮点数当中默认类型是double。如果一定要使用float类型,需要加上一个后缀F。
如果是整数,默认为int类型,如果一定要使用long类型,需要加上一个后缀L。推荐使用大写字母后缀。 - 如果使用byte或者short类型的变量,那么右侧的数据值不能超过左侧类型的范围。
- 没有进行赋值的变量,不能直接使用;一定要赋值之后,才能使用。
数据类型转换
Java程序中要求参与的计算的数据,必须要保证数据类型的一致性
,如果数据类型不一致将发生类型的转换。
3.1 自动转换(隐式)
规则:将取值范围小的类型
自动提升为取值范围大的类型
。 浮点型数据比整数数据的范围大
一个int类型变量和一个byte类型变量进行加法运算,运算结果,变量的类型将是int类型。
public static void main(String[] args) {
int i = 1;
byte b = 2;
// byte x = b + i; // 报错
//int类型和byte类型运算,结果是int类型
int j = b + i;
System.out.println(j);
}
转换规则
范围小的类型向范围大的类型提升,byte、short、char
运算时直接提升为int
。
byte、short、char‐‐>int‐‐>long‐‐>float‐‐>double
3.2 强制转换(显示)
将取值范围大的类型
强制转换成取值范围小的类型
。比较而言,自动转换是Java自动执行的,而强制转换需要我们自己手动执行。
转换格式:
数据类型 变量名 =(数据类型)被转数据值;
// double类型数据强制转成int类型,直接去掉小数点。
int i = (int)1.5;
public static void main(String[] args) {
//short类型变量,内存中2个字节
short s = 1;
/*
出现编译失败
s和1做运算的时候,1是int类型,s会被提升为int类型
s+1后的结果是int类型,将结果在赋值会short类型时发生错误
short内存2个字节,int类型4个字节
必须将int强制转成short才能完成赋值
*/
s = s + 1;//编译失败
s = (short)(s+1);//编译成功
}
转换原理图解
3.3 类型转换注意事项
- 强制类型转换一般不推荐使用,因为有可能发生精度损失、数据溢出。
// double --> int,强制类型转换
int num3 = (int) 3.99;
System.out.println(num3); // 3,这并不是四舍五入,所有的小数位都会被舍弃掉
byte/short/char
这三种类型都可以发生数学运算,例如加法“+”。
char zifu1 = 'A'; // 这是一个字符型变量,里面是大写字母A
System.out.println(zifu1 + 1); // 66,也就是大写字母A被当做65进行处理
// 计算机的底层会用一个数字(二进制)来代表字符A,就是65
// 一旦char类型进行了数学运算,那么字符就会按照一定的规则翻译成为一个数字
byte/short/char
这三种类型在运算的时候,都会被首先提升成为int类型,然后再计算。
byte num4 = 40; // 注意!右侧的数值大小不能超过左侧的类型范围
byte num5 = 50;
//错误: “不兼容的类型,从int到byte可能会有损失”
byte result1 = num4 + num5; // byte + byte --> int + int --> int
//正确:应该使用int数据类型接收,byte类型计算时已经提升为int类型
int result1 = num4 + num5;
System.out.println(result1); // 理论应该输出90
short num6 = 60;
// byte + short --> int + int --> int
// int强制转换为short:注意必须保证逻辑上真实大小本来就没有超过short范围,否则会发生数据溢出
short result2 = (short) (num4 + num6);
- boolean类型不能发生数据类型转换。布尔类型不能被当作1或者0。
3.4 ASCII编码
数字和字符的对照关系表(编码表):
- ASCII码表:American Standard Code for Information Interchange,美国信息交换标准代码。
- Unicode码表:万国码。也是数字和符号的对照关系,开头0-127部分和ASCII完全一样,但是从128开始包含有更多字符。
字符 | 数值 |
---|---|
0 | 48 |
9 | 57 |
A | 65 |
Z | 90 |
a | 97 |
z | 122 |
运算符
4.1 算数运算符
-
运算符:进行特定操作的符号。例如:+
-
表达式:用运算符连起来的式子叫做表达式。例如:20 + 5。又例如:a + b
+ | - | * | / | % | ++ | --
注意:- 对于一个整数的表达式来说,除法用的是整除,整数除以整数,结果仍然是整数。只看商,不看余数。只有对于整数的除法来说,取模运算符才有余数的意义。
- 一旦运算当中有不同类型的数据,那么结果将会是数据类型范围大的那种。即计算时类型会统一到范围大的类型在计算。
-
加号的用法:
- 对于数值来说,那就是加法。
- 对于字符char类型来说,在计算之前,char会被提升成为int,然后再计算。
char类型字符,和int类型数字,之间的对照关系表:ASCII、Unicode - 对于字符串String(首字母大写,并不是关键字)来说,加号代表字符串连接操作。
任何数据类型和字符串进行连接的时候,结果都会变成字符串。
String str2 = "Java"; // String + int --> String System.out.println(str2 + 20); // Java20 // 优先级问题 // String + int + int // String + int // String System.out.println(str2 + 20 + 30); // Java2030 System.out.println(str2 + (20 + 30)); // Java50
-
自增自减 ++/--
- 在单独使用的时候,前++和后++没有任何区别。也就是:++num;和num++;是完全一样的。
- 在混合的时候,有【重大区别】
A. 如果是【前++】,那么变量【立刻马上+1】,然后拿着结果进行使用。 【先加后用】
B. 如果是【后++】,那么首先使用变量本来的数值,【然后再让变量+1】。 【先用后加】
int x = 10; int y = 20; // 11 + 20 = 31 int result3 = ++x + y--; System.out.println(result3); // 31 System.out.println(x); // 11 System.out.println(y); // 19
注意:只有变量才能使用自增、自减运算符。常量不可发生改变,所以不能用。
30++; // 错误写法!常量不可以使用++或者--
4.2 赋值运算符
赋值运算符包括 | |
---|---|
= | 等于号 |
+= | 加等于 |
-= | 减等于 |
*= | 乘等于 |
/= | 除等于 |
%= | 取模等 |
- 只有变量才能使用赋值运算符,常量不能进行赋值。
- 复合赋值运算符其中隐含了一个强制类型转换。
byte num = 30;
// num = num + 5;
// num = byte + int
// num = int + int
// num = int
// num = (byte) int
num += 5;
System.out.println(num); // 35
4.3 比较运算符
比较运算符包括: | |
---|---|
== | 比较符号两边数据是否相等,相等结果是true。 |
< | 比较符号左边的数据是否小于右边的数据,如果小于结果是true。 |
| 比较符号左边的数据是否大于右边的数据,如果大于结果是true。
<= | 比较符号左边的数据是否小于或者等于右边的数据,如果小于结果是true。
= | 比较符号左边的数据是否大于或者等于右边的数据,如果小于结果是true。
!= | 不等于符号 ,如果符号两边的数据不相等,结果是true。
- 比较运算符的结果一定是一个boolean值,成立就是true,不成立就是false
- 如果进行多次判断,不能连着写。
数学当中的写法,例如:1 < x < 3
程序当中【不允许】这种写法。因为1<x
的结果时boolean类型
,再与3(int型)比较类型不一致。
4.4 逻辑运算符
逻辑运算符包括 | ||
---|---|---|
与(并且) | && | 全都是true,才是true;否则就是false |
或(或者) | || | 至少一个是true,就是true;全都是false,才是false |
非(取反) | ! | 本来是true,变成false;本来是false,变成true |
**与“&&”,或“ | ”,具有短路效果:如果根据左边已经可以判断得到最终结果,那么右边的代码将不再执行,从而节省一定的性能。** | |
注意事项: |
- 逻辑运算符只能用于boolean值。
- 与、或需要左右各自有一个boolean值,但是取反只要有唯一的一个boolean值即可。
- 与、或两种运算符,如果有多个条件,可以连续写。
两个条件:条件A && 条件B
多个条件:条件A && 条件B && 条件C
TIPS:
对于1 < x < 3的情况,应该拆成两个部分,然后使用与运算符连接起来:
int x = 2;
1 < x && x < 3
int a = 10;
// false && ...
System.out.println(3 > 4 && ++a < 100); // false
System.out.println(a); // 10 短路!
System.out.println("============");
int b = 20;
// true || ...
System.out.println(3 < 4 || ++b < 100); // true
System.out.println(b); // 20 短路!
4.5 三元运算符
- 一元运算符:只需要一个数据就可以进行操作的运算符。例如:取反!、自增++、自减--
- 二元运算符:需要两个数据才可以进行操作的运算符。例如:加法+、赋值=
- 三元运算符:需要三个数据才可以进行操作的运算符。
数据类型 变量名称 = 条件判断 ? 表达式A : 表达式B;
流程:
首先判断条件是否成立:
- 如果成立为true,那么将表达式A的值赋值给左侧的变量;
- 如果不成立为false,那么将表达式B的值赋值给左侧的变量;
二者选其一。
注意事项:
- 必须同时保证表达式A和表达式B都符合左侧数据类型的要求。
int result = 3 > 4 ? 2.5 : 10; // 错误写法!
- 三元运算符的结果必须被使用。
a > b ? a : b; // 错误写法!
方法入门
方法:就是将一个功能抽取出来,把代码单独定义在一个大括号内,形成一个单独的功能。当我们需要这个功能的时候,就可以去调用。这样即实现了代码的复用性,也解决了代码冗余的现象
定义一个方法的格式:
public static void 方法名称() {
方法体
}
- 方法名称的命名规则和变量一样,使用小驼峰。
- 方法体:也就是大括号当中可以包含任意条语句。
注意事项:
- 方法定义的先后顺序无所谓。
- 方法的定义不能产生嵌套包含关系。
- 方法定义好了之后,不会执行的。如果要想执行,一定要进行方法的【调用】。
如何调用方法,格式:
方法名称();
编译器的两点优化 !!
- 对于byte/short/char三种类型来说,如果右侧赋值的数值没有超过范围,那么javac编译器将会自动隐含地为我们补上一个(byte)(short)(char)。
- 如果没有超过左侧的范围,编译器补上强转。
- 如果右侧超过了左侧范围,那么直接编译器报错。
public class Demo12Notice {
public static void main(String[] args) {
// 右侧确实是一个int数字,但是没有超过左侧的范围,就是正确的。
// int --> byte,不是自动类型转换
byte num1 = /*(byte)*/ 30; // 右侧没有超过左侧的范围
System.out.println(num1); // 30
// byte num2 = 128; // 报错,右侧超过了左侧的范围
// int --> char,没有超过范围
// 编译器将会自动补上一个隐含的(char)
char zifu = /*(char)*/ 65;
System.out.println(zifu); // A
}
}
- 编译器的常量优化
/*
在给变量进行赋值的时候,如果右侧的表达式当中全都是常量,没有任何变量,
那么编译器javac将会直接将若干个常量表达式计算得到结果。
short result = 5 + 8; // 等号右边全都是常量,没有任何变量参与运算
编译之后,得到的.class字节码文件当中相当于【直接就是】:
short result = 13;
右侧的常量结果数值,没有超过左侧范围,所以正确。
这称为“编译器的常量优化”。
但是注意:一旦表达式当中有变量参与,那么就不能进行这种优化了。
*/
public class Demo13Notice {
public static void main(String[] args) {
short num1 = 10; // 正确写法,右侧没有超过左侧的范围,
short a = 5;
short b = 8;
// short + short --> int + int --> int
// short result = a + b; // 错误写法!左侧需要是int类型
// 右侧不用变量,而是采用常量,而且只有两个常量,没有别人
short result = 5 + 8;
System.out.println(result);
short result2 = 5 + a + 8; // 18
}
}
流程控制语句
1. 顺序结构
2. 判断语句 if
// 1) 单if语句
if(关系表达式){
语句体;
}
// 2) 标准的if-else语句
if(关系表达式) {
语句体1;
}else {
语句体2;
}
// 3)嵌套if-else if else
if (判断条件1) {
执行语句1;
} else if (判断条件2) {
执行语句2;
}
...
}else if (判断条件n) {
执行语句n;
} else {
执行语句n+1;
}
3. 选择语句 switch
switch(表达式) {
case 常量值1:
语句体1;
break;
case 常量值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
switch语句使用的注意事项:
-
多个case后面的数值不可以重复。
-
switch后面小括号当中只能是下列数据类型:
基本数据类型:byte/short/char/int (其他的基本类型不可以使用)
引用数据类型:String字符串、enum枚举 -
switch语句格式可以很灵活:前后顺序可以颠倒,而且break语句还可以省略。
“匹配哪一个case就从哪一个位置向下执行,直到遇到了break或者整体结束为止。” 具有穿透性
4. 循环语句
循环结构的基本组成部分,一般可以分成四部分:
- 初始化语句:在循环开始最初执行,而且只做唯一一次。
- 条件判断:如果成立,则循环继续;如果不成立,则循环退出。
- 循环体:重复要做的事情内容,若干行语句。
- 步进语句:每次循环之后都要进行的扫尾工作,每次循环结束之后都要执行一次。
// for 循环
for(初始化表达式①; 布尔表达式②; 步进表达式④){
循环体③
}
// while 循环
初始化表达式①
while(布尔表达式②){
循环体③
步进表达式④
}
// do-while 循环
初始化表达式①
do{
循环体③
步进表达式④
}while(布尔表达式②);
三种循环的区别:
- 如果条件判断从来没有满足过,那么for循环和while循环将会执行0次,但是do-while循环会执行至少一次。
- for循环的变量在小括号当中定义,只有循环内部才可以使用。while循环和do-while循环初始化语句本来就在外面,所以出来循环之后还可以继续使用。
5. 循环控制语句
break
- 可以用在switch语句当中,一旦执行,整个switch语句立刻结束。
- 还可以用在循环语句当中,一旦执行,整个循环语句立刻结束。打断循环。
关于循环的选择,有一个小建议:凡是次数确定的场景多用for循环;否则多用while循环。
continue
一旦执行,立刻跳过当前次循环剩余内容,马上开始下一次循环。
6. 死循环
即循环中的条件永远为true,死循环的是永不结束的循环。例如:while(true){}
7. 嵌套循环
所谓嵌套循环,是指一个循环的循环体是另一个循环。比如for循环里面还有一个for循环,就是嵌套循环。总共的循环次数=外循环次数*内循环次数
for(初始化表达式①; 循环条件②; 步进表达式⑦) {
for(初始化表达式③; 循环条件④; 步进表达式⑥) {
执行语句⑤;
}
}