大纲
- 八大基本数据类型
- 运算符
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- 位运算符
- 三元运算符
- 运算符优先级
- 趣味题
八大基本数据类型
基本数据类型 | 默认值 | 包装类 | 占用空间 | 取值范围 | 包装类型的缓存区间 |
byte | 0 | Byte | 1 Byte | -128 ~ 127 | -128~127 |
short | 0 | Short | 2 Byte | -2^15 ~ 2^15-1 | -128~127 |
int | 0 | Integer | 4 Byte | -2^31 ~ 2^31-1 | -128~127 |
long | 0L | Long | 8 Byte | -2^63 ~ 2^63-1 | -128~127 |
float | 0f | Float | 4 Byte | -2^128 ~ 2^128 | 无 |
double | 0d | Double | 8 Byte | -2^1024 ~ 2^1024 | 无 |
boolean | false | Boolean | false/true | 无 | |
char | ’u0000’ | Character | 2 Byte | 0 ~ 65535 | 0~127 |
对于boolean类型的占用空间,《Java虚拟机规范》给出了单独使用4个字节、boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来
特殊的几个数据类型写法:
// long类型需要加 l / L(推荐用大写区分)
long l = 1L;
// float类型需要加 f / F
float f = 0.1f;
// char类型是由单引号括起来的单个字符
char c = 'a';
基本数据类型自动向上转型关系:
byte
, short
, char
→ int
→ long
→ float
→ double
byte
, short
, char
三者之间只有 byte
可以转为 short
基本数据类型在作为类成员时才会有默认值,作为局部变量如果没有进行显式初始化,在使用的时候会报编译时异常
多种基本数据类型混合运算时会先转换成容量最大的数据类型再进行运算
char类型在参与算术运算时会转换为ASCII码对应的值
System.out.println('*' + '\t' + '*'); // 93
System.out.println("*" + '\t' + '*'); // * *
byte,short,char三者参与运算时会默认转换为int类型再运算
short s, s2 = 1;
short s3 = s + s2; // 编译异常,需要用int接收
浮点数之间的等值判断,基本数据类型不能用==
来比较,包装数据类型不能用equals
来判断。
float a = 1.0f - 0.9f; // 0.100000024 精度丢失
float b = 0.9f - 0.8f; // 0.099999964 精度丢失
System.out.println(a == b); // false
运算符
算术运算符
+
、-
、*
、/
、%
对于除运算,除数与被除数都为整型时,如果除不尽会直接舍弃小数取整
int i = 1 / 5.0; // 编译异常,需要强转为double
int ii = 1 / 2; // 0 0.5会直接取整
对于整型数a,b来说,取模运算或者取余运算的方法都是:
1.求整数商: c = a/b;
2.计算模或者余数: r = a - c * b
取模运算和取余运算在第一步不同: 取余运算在取c的值时,向0方向舍入(正数向下,负数向上舍入);而取模运算在计算c的值时,向负无穷方向舍入(向下舍入)。java实现是取余,python实现是取模。
简单记就是:结果的正负看左边
System.out.println(10 % 5.1); // 4.9
System.out.println(-10 % -5.1); // -4.9
System.out.println(10 % -5.1); // 4.9
System.out.println(-10 % 5.1); // -4.9
应用:
求模运算结果都比模数小(控制大小)
任何数模以2不是0就是1(开关控制)
赋值运算符
=
、+=
、-=
、*=
、/=
、%=
、++
、--
自增(自减)符号在前先自增(自减)再运算,自增(自减)符号在后先运算后自增(自减) 例:
int a = 0;
int b = 1;
System.out.println(++a + b++); // 2
System.out.println(a); // 1
System.out.println(b); // 2
+=
、-=
、*=
、/=
、%=
会自动向下转型,存在丢失精度的风险 例:
byte b = 2;
b += 126
system.out.pritln(b) // -128 byte范围是-128~127
比较运算符
==
、!=
、>
、<
、>=
、<=
==
判断两个对象的地址是否相等。基本数据类型比较的是值,引用数据类型比较的是内存地址。
因为java只有值传递,对于 ==
来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。
逻辑运算符
&&
(逻辑与,若左边为false则右边不进行运算,同真才为true)
||
(逻辑或,若左边为true则右边不进行运算,有一个为真即为true)
!
(非运算) !true = false
位运算符
&
(按位与,两边都进行运算,除了做逻辑运算,还能做算术运算) 例: 6&2 = 2,化二进制有假(0)为假
|
(按位或,两边都进行运算,除了做逻辑运算,还能做算术运算) 例:6|3 = 7,化二进制有真(1)为真
^
(异或,除了做逻辑运算,还能做算术运算)
例:6^3 = 5,化二进制相同为假不同为真
一个数异或另一个数两次结果还是这个数
(i^n^n) == (i^0) == i
<<
(左移,乘2的幂运算,空位补0) 例: 5<<3 = 5*2^3 = 40
>>
(有符号整数右移,算术右移,除2的幂运算,最高位是什么空位就补什么) 例:5>>3 = 5/2^3 = 0
>>>
(无符号整数右移,逻辑右移,无论最高位是什么空位都补0)
~
(取反,一个数取反即相反数-1) 例: ~n = (-n) - 1
三元运算符
条件表达式?表达式1:表达式2,条件表达式为true则执行表达式1,否则执行表达式2
int x = a > b ? a : b; // 取两位数中的较大值
三元运算符的类型转换规则:
- 若两个表达式类型相同,则返回值类型为该类型
- 若两个表达式类型不同,且不能进行转化,则返回的是他们最接近的父类类型
boolean condition = false;
Serializable serializable = condition ? "" : 1.0;
AbstractList<Object> abstractList = condition ? new ArrayList<>() : new LinkedList<>();
- 若其中一个表达式X是
char
,byte
,short
类型(或他们的包装类),另一个Y是int
类型,若在编译期就能判断出Y在X的范围内,Y会被当成X类型返回X类型,反之则X向上转型为Y返回类型为Y。如果不是这几种则会发生自动向上转型
boolean condition = false;
char c = 'c';
byte b = 1;
short s = 1;
int i = 1;
// 98自动转为char
char r = condition ? c : 98;
// 98自动转为byte
byte r2 = condition ? b : 98;
// 98自动转为short
short r3 = condition ? s : 98;
// 128超出了byte的范围,b自动转为int
int r4 = condition ? b : 128;
// 前面已经声明了i为int,则不会自动转化为byte
int r5 = condition ? b : i;
// float自动向上转型为double
double r6 = condition ? 50f : 100d;
- 若遇到表达式为包装类型,则会先转化为基本数据类型,然后按照基本数据类型的自动转化规则进行转化,返回值为优先级最高的基本数据类型
boolean condition = false;
Character c = null;
Integer a = 127;
// c和a都会调用.xxxValue()方法转为基本数据类型,所以返回int类型
// 但是运行时c为null调用charValue()会报NullPointerException
int i = condition ? c : a;
这点大多数人会忽略,所以慎用三元运算符
运算符优先级
运算符 | 结合性 |
[ ] . ( ) (方法调用) | 从左向右 |
! ~ ++ – +(正) -(负) | 从右向左 |
* / % | 从左向右 |
+ - | 从左向右 |
<< >> >>> | 从左向右 |
< <= > >= instanceof | 从左向右 |
== != | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
| | 从左向右 |
&& | 从左向右 |
|| | 从左向右 |
?: | 从右向左 |
= | 从右向左 |
趣味题
不使用第三方变量,交换两个变量的值
int a = 0;
int b = 1;
// 解一
a = a + b;
b = a - b; // b = a + b - b
a = a - b; // a = a + b - a
// 解二
a = a ^ b;
b = a ^ b; // b = a ^ b ^ b
a = a ^ b; // a = a ^ b ^ a
判断一个数是否是2的n次幂
n > 0 && (n & (n - 1)) == 0