文章目录
前言
变量指的是程序运行时可变的量. 相当于开辟一块内存空间来保存一些数据.
类型则是对变量的种类进行了划分, 不同的类型的变量具有不同的特性.
我们所讨论的 “变量” 主要和我们的 “内存” 这样的硬件设备密切相关。
这一切的一切,就不得不提到冯诺依曼的五大体系了
一、各种各样的数据类型
基本类型/内置类型 | 包装类 | 大小(字节) | 取值范围 |
---|---|---|---|
int | Integer | 4 | -231~231-1 |
long | Long | 8 | -263~263-1 |
double | Double | 8 | 存储参考C语言 |
float | Float | 4 | 存储参考C语言 |
char | Character | 2 | 0~65535 |
byte | Byte | 1 | -128~127 |
short | Short | 2 | -215~215-1 |
boolean | Boolean | 注1 | true/false |
注1:JVM标准并未说明是几个字节,没有明确的大小,有些书上说1bit,有些书上说1字节,如果遇见选择题,见机行事
1.1整型变量与长整型变量
由于int类型的范围还不够大,很容易超出,因此Java提供了更大范围的变量,即长整形
1.2双精度浮点型变量与单精度浮点型变量
1.3字符类型变量
1.4字节类型变量
1.5短整型变量
1.6布尔类型变量
1.7字符串类型变量
一般常见多用的转义字符
转义字符 | 释义 |
---|---|
\‘ | 用于表示字符常量’ |
\“ | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 |
\n | 换行 |
\b | 退格符 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
二、变量的命名规则
硬性指标:
- 一个变量名只能包含数字, 字母, 下划线,$
- 数字不能开头.
- 变量名是大小写敏感的. 即 num 和 Num 是两个不同的变量.
注意: 虽然语法上也允许使用中文/美元符($)命名变量, 但是 强烈 不推荐这样做.
软性指标:
- 变量命名要具有描述性, 见名知意。
- 变量名不宜使用拼音(但是不绝对)。
- 变量名的词性推荐使用名词。
- 变量命名、方法的名称推荐小驼峰命名法, 当一个变量名由多个单词构成的时候, 除了第一个单词之外, 其他单词首字母都大写。
- 类名、接口推荐用大驼峰命名法,当一个变量名由多个单词构成的时候, 所有单词的首字母都为大写。
三、常量
上面讨论的都是各种规则的变量, 每种类型的变量也对应着一种相同类型的常量.
常量指的是运行时类型不能发生改变。
字面值常量:
举例 | 解释 |
---|---|
10 | int 字面值常量(十进制) |
010 | int 字面值常量(八进制) 由数字 0 开头. 010 也就是十进制的 8 |
0x10 | int 字面值常量(十六进制) 由数字 0x 开头. 0x10 也就是十进制的 16 |
10L | long 字面值常量. 也可以写作 10l (小写的L) |
1.0 | double 字面值常量. 也可以写作 1.0d 或者 1.0D |
1.5e2 | double 字面值常量. 科学计数法表示. 相当于 1.5 * 10^2 |
1.0f | float 字面值常量, 也可以写作 1.0F |
true | boolen 字面值常量, 同样的还有 false |
‘a’ | char 字面值常量, 单引号中只能有一个字符 |
“abc” | String 字面值常量, 双引号中可以有多个字符 |
final 关键字修饰的常量
✒️ 代码举例:
注意:
- final 修饰形成常量时,放在类型的前面
- 修饰的常量赋值后不能进行修改
- 修饰的常量简易是大写,方便与变量进行区分
- final 还可以修饰函数(密封方法),修饰类(密封类)
四、类型转换
Java 作为一个强类型编程语言, 当不同类型之间的变量相互赋值的时候, 会有教严格的校验.
✒️ 代码举例:
//int和long/double相互赋值
int a = 10;
long b = 20;
a = b; // 编译出错, 提示可能会损失精度.
b = a; // 编译通过.
int a = 10;
double b = 1.0;
a = b; // 编译出错, 提示可能会损失精度.
b = a; // 编译通过
//boolean和其他类型相互赋值
int a = 10;
boolean b = true;
b = a; // 编译出错, 提示不兼容的类型
a = b; // 编译出错, 提示不兼容的类型
//强制类型转换
int a = 0;
double b = 10.5;
a = (int)b;
int a = 10;
boolean b = false;
b = (boolean)a; // 编译出错, 提示不兼容的类型
📖代码总结:
- 转换时注意等号左右两边的数据类型的字节大小( double 占8个字节,int 占4个字节),表示的数字的宽度( double 能接收小数和整数,int 只能接收整数)。不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型
- boolean 不能和任何其他的数据类型之间转换,因为毫不相干
- 强制类型转换可能会导致精度丢失. 强转的例子中, 赋值之后, 10.5 就变成 10 了, 小数点后面的部分被忽略
五、数值提升
✒️ 代码举例:
int a = 10;
long b = 20;
int c = a + b; // 编译出错, 提示将 long 转成 int 会丢失精度
long d = a + b; // 编译通过.
📖代码总结:
当 int 和 long 混合运算的时候, int 会提升成 long, 得到的结果仍然是 long 类型, 需要使用 long 类型的变量来接收结果. 如果非要用 int 来接收结果, 就需要使用强制类型转换.
不同类型的数据混合运算, 范围小的会提升成范围大的.
✒️ 代码举例:
byte a = 10;
byte b = 20;
byte c1 = a + b;
System.out.println(c1);
//正确操作
byte c2 = (byte)(a + b);
System.out.println(c2);
//正确操作
byte c3 = 10 + 20;
//由于10 +20是一个常量,编译的时候,该代码视为byte c3 = 30;
System.out.println(c3);
//而最上面的代码,只有在程序运行的时候才会知道a,b中放的值是多少
📖代码总结:
byte 和 byte 都是相同类型, 但是出现编译报错. 原因是, 虽然 a 和 b 都是 byte, 但是计算 a + b 会先将 a 和 b 都
提升成 int, 再进行计算, 得到的结果也是 int, 这是赋给 c, 就会出现上述错误.
由于计算机的 CPU 通常是按照 4 个字节为单位从内存中读写数据. 为了硬件上实现方便, 诸如 byte 和 short 这种低于
4 个字节的类型, 会先提升成 int, 再参与计算.
六、花样的运算符
6.1算术运算符
基本四则运算符 + (加) - (减) * (乘) / (除) % (取余)
✒️ 代码举例:
int a = 1;
int b = 2;
int c = 0;
System.out.println(a + b); //3
System.out.println(a - b); //-1
System.out.println(a * b); //2
System.out.println(a / b); //0
System.out.println(a / c); //报错
System.out.println(11.5 % 2.0); //1.5
📖代码总结:
- int / int 结果还是 int, 需要使用 double 来计算
- 0 不能作为除数
- % 表示取余, 不仅仅可以对 int 求模, 也能对 double 来求模
增量赋值运算符 += -= *= /= %=
自增/自减运算符 ++ –
✒️ 代码举例:
int a = 10;
a += 1; // 等价于 a = a + 1
System.out.println(a); //11
short m = 10;
m = m + 19;//报错
//19是int类型,m与之相加后结果为int类型,在为强制类型转换时,会产生错误
m += 19;//正确
//符合运算符会帮助进行类型的转换,该代码相当于m = (short)(m + 19);
System.out.println(m);
System.out.println(b);
int a = 10;
int b = ++a;
System.out.println(b); //11
int c = a++;
System.out.println(c); //10
a = a++;
System.out.println(a); //10,看反汇编方可知道原因,了解即可
📖代码总结:
如果不取自增运算的表达式的返回值, 则前置自增和后置自增没有区别.
如果取表达式的返回值, 则前置自增的返回值是自增之后的值, 后置自增的返回值是自增之前的值
6.2关系运算符
== != < > <= >=
✒️ 代码举例:
int a = 10;
int b = 20;
System.out.println(a == b); //false
System.out.println(a != b); //true
System.out.println(a < b); //true
System.out.println(a > b); //false
System.out.println(a <= b); //true
System.out.println(a >= b); //false
📖代码总结:
关系运算符的表达式返回值都是 boolean 类型
6.3逻辑运算符
&& || !
✒️ 代码举例:
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b && b < c); //true
System.out.println(a < b || b < c); //true
System.out.println(!(a < b)); //false
//短路求值
System.out.println(10 > 20 && 10 / 0 == 0); //false
System.out.println(10 < 20 || 10 / 0 == 0); //true
📖代码总结:
逻辑运算符规则:
- 逻辑与(&&)两个操作数都为 true, 结果为 true, 否则结果为 false
- 逻辑或(||)两个操作数都为 false, 结果为 false, 否则结果为 true
- 操作数为 true, 结果为 false; 操作数为 false, 结果为 true(这是个单目运算符, 只有一个操作数)
短路求值:
计算 10 / 0 会导致程序抛出异常. 但是上面的代码却能正常运行, 说明 10 / 0 并没有真正被求值
对于 && , 如果左侧表达式值为 false, 则表达式的整体的值一定是 false, 无需计算右侧表达式
对于 ||, 如果左侧表达式值为 true, 则表达式的整体的值一定是 true, 无需计算右侧表达式.
& 和 | 如果操作数为 boolean 的时候, 也表示逻辑运算. 但是和 && 以及 || 相比, 它们不支持短路求值
6.4位运算符
& | ~ ^
位操作表示按二进制位运算. 计算机中都是使用二进制来表示数据的(01构成的序列), 按位运算就是在按照二进制位的
每一位依次进行计算
注意:
当 & 和 | 的操作数为整数(int, short, long, byte) 的时候, 表示按位运算, 当操作数为 boolean 的时候, 表示逻辑运算.
6.5移位运算
<< >> >>>
移位运算符都是按照二进制位来运算。
注意:
- 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方.
- 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方.
- 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替.
- 移动负数位或者移位位数过大都没有意义.
6.6 条件运算符
表达式1 ? 表达式2 : 表达式3
规则:
当 表达式1 的值为 true 时, 整个表达式的值为 表达式2 的值;
当 表达式1 的值为 false 时, 整个表达式的值为 表达式3 的值;
✒️ 代码举例:
// 求两个整数的最大值
int a = 10;
int b = 20;
int max = a > b ? a : b;
七、运算符的优先级
Java 语言中运算符的优先级共分为 14 级,其中 1 级最高,14 级最低。在同一个表达式中运算符优先级高的先执行。下表列出了所有的运算符的优先级以及结合性。
优先级 | 运算符 | 结合性 |
---|---|---|
1 | ()、[]、{} | 从左向右 |
2 | !、+(正)、-(负)、~、++、– | 从右向左 |
3 | *、/、% | 从左向右 |
4 | +(加)、-(减) | 从左向右 |
5 | <<、>>、>>> | 从左向右 |
6 | <、<=、>、>=、instanceof | 从左向右 |
7 | ==、!= | 从左向右 |
8 | &(按位与) | 从左向右 |
9 | ^ | 从左向右 |
10 | | | 从左向右 |
11 | && | 从左向右 |
12 | || | 从左向右 |
13 | ?: | 从右向左 |
14 | =、+=、-=、*=、/=、&=、|=、^=、~=、<<=、>>=、>>>= | 从右向左 |
具体的规则我们记不清, 只需要在可能存在歧义的代码中加上括号即可。
完!