基本类型
在java里有八种基本类型及每一种类型都对应了一种包装类
- 在了解基本数据类型之前需要说一下,java的所有类型的字节大小都和平台没有关系。
- 所有整型没有无符号概念。
short(短整型)
- short 占用 2 个字节, 表示的数据范围是 -32768~32767
- 因为范围比较小,不是必须的话,不推荐使用。
使用示例
short value = 10;
System.out.println(value);
注意事项
short a = 10;
short b = 20;
short c = a + b;
System.out.println(c);
当运行这段代码的时候会出现报错。
即使short 和 short 都是相同类型, 但是会出现编译报错. 原因是, 虽然 a 和 b 都是 short变量, 但是计算 a + b 会先将 a 和 b 都提升成 int, 再进行计算, 得到的结果也是 int, 这是赋给 c, 就会出现上述错误
正确的写法
short a = 10;
short b = 20;
short c = (short)(a + b);
System.out.println(c);
给a+b的表达式强制转换为short类型则不会报错。
byte(字节类型)
- 字节类型也属于整型的一种,不过它的字节大小是1,取值范围是-128~127
使用示例
byte value = 10;
System.out.println(value);
注意事项
- byte类型和short类型都是低于4个字节,在运算时均会发生数值提示的现象,使用时需要更加注意
- 因为范围比较小,不是必须的话,不推荐使用。
int( 整型)
使用示例
int num = 10; // 定义一个整型变量
System.out.println(num) ;
- 在java中int类型就是4个字节,跟系统无关。
- 由于在java中是没有无符号整型概念的,所以int的取值范围是 -2^31 ~ 2^31-1。
以下代码可以查看int的数据范围。
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE); // int 的最大值
System.out.println(Integer.MIN_VALUE); // int 的最小值
}
运行截图
如果运算的结果超出了int的取值范围,则数据就会溢出
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE+1); // int 的最大值加1会溢出
System.out.println(Integer.MIN_VALUE-1); // int 的最小值-1会溢出
}
运行截图
有细心的读者会发现,int所表示的最大值加1溢出后变成了最小值,而最小值减1后变成了最大值,我们可以把类型范围表示看成一个圆形
中间的是分界线,如果超过了最大值则就变成了最小值,这种概念可以应用与所有的整型类型。
long(长整型)
对于int能表示21亿,这样的数字对于当前大数据时代来说,是很容易溢出的,针对这种情况, 我们就需要使用更大范围的数据类型来表示了. Java 中提供了 long 类型.
使用示例
long num = 10L; // 定义一个长整型变量, 初始值写作 10l 也可以(小写的 L, 不是数字1).
System.out.println(num) ;
- 需要注意的是初始化设定的值为 10L ,表示一个长整型的数字,10l 也可以.
- 使用 10 初始化也可以, 10 的类型是 int, 10L 的类型是 long, 使用 10L 或者 10l 更好一些.(这里推荐用大写的L,因为有些字体小写的l可能容易被看成数字1)
- java中long占8个字节,取值范围在 -2^63 ~ 2^63-1
使用以下代码查看 Java 中的长整型数据范围
public static void main(String[] args) {
System.out.println(Long.MAX_VALUE);
System.out.println(Long.MIN_VALUE);
}
运行结果
这个数据范围远超过 int 的表示范围. 足够绝大部分的工程场景使用.
double(双精度浮点型)
- 在java中小数默认是double类型。
使用示例
double num = 1.0;//定义一个浮点型变量
System.out.println(num)
浮点型和整型有什么不一样呢?来看下面一段代码。
public static void main(String[] args) {
int a = 1;
int b = 2;
System.out.println(a / b);
}
如果站在数学角度来讲,得到的应该是0.5,可运行结果得到的是0。
运行截图
因为a和b是int类型变量,所以得到的结果也会是int类型的值,而int是无法储存小数的。如果想要得到小数,那我们就需要把int改成double。
public static void main(String[] args) {
double a = 1.0;
double b = 2.0;
System.out.println(a / b);
}
运行截图
来看一段有趣的代码
public static void main(String[] args) {
double a = 1.1;
double b = 1.1;
System.out.println(a * b);
}
运行截图
理论来讲,得出的结果应该是1.21,为什么后面还多了个2?这是因为Java 中的 double 虽然也是 8 个字节, 但是浮点数的内存布局和整数差别很大, 不能单纯的用 2 ^ n 的形式表示数据范围,Java 的 double 类型的内存布局遵守IEEE 754 标准(和C语言一样), 尝试使用有限的内存空间表示可能无限的小数, 势必会存在一定的精度误差,关于IEEE 754标准,有兴趣的读者可以去度娘了解一下,这里就不多介绍了。
float(单精度浮点型)
- float 类型在 Java 中占4个字节, 同样遵守 IEEE 754 标准. 由于表示的数据精度范围较小, 一般在工程上用到浮点数都优先考虑 double, 不太推荐使用 float.
使用示例
float num = 1.0f; // 写作 1.0F 也可以
System.out.println(num);
初始化需要注意在值需要加一个大写的F或者小写的f来表示这是一个float类型的小数,因为在java中小数是默认是double型的,不加f的话就相当于把一个double类型的值赋给float类型,则会发生精度丢失的错误。
char(字符类型)
- char类型不能存储负数, 取值范围在是~65535
- Java 中使用 Unicode 表示字符. 因此一个char占用2个字节, 表示的字符种类更多, 包括中文
- Java 中使用 单引号 + 单个字母 的形式表示字符字面值.
使用示例
public static void main(String[] args) {
char a = 'A';
char b = 'B';
char c = 65;//对应Unicode表上的字符'A'
char d = '中';
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
运行结果
boolean(布尔类型)
使用示例
boolean value = true;
System.out.println(value);
- boolean 类型的变量只有两种取值, true 表示真, false 表示假.
- Java 的 boolean 类型和 int 不能相互转换, 不存在 1 表示 true, 0 表示 false 这样的用法.
- boolean 类型有些 JVM 的实现是占 1 个字节, 有些是占 1 个比特位, 这个没有明确规定.
小结
- 不同类型的数据混合运算, 范围小的会提升成范围大的.
- 对于 short, byte 这种比 4 个字节小的类型, 会先提升成 4 个字节的 int , 再运算
- 更推荐在代码中避免不同类型混用的情况, 来规避类型转换和类型提升的问题
基本数据类型介绍到这,最后附上一张数据类型概况图,关于引用数据类型,会在以后的博客中讲。
算术运算符
四则运算规则比较简单,这里我就讲比较容易出错的取余和除法运算符。
除 /
除法在进行运算的时候,会根据类型不同得出不同结果。
public static void main(String[] args) {
System.out.println(12 / 5);
System.out.println(12 / (float)5);
}
运行截图
从运行结果我们可以看到,两个数值一样类型不一样得到的结果不一样,需要注意除法有两种规则。
- 如果两个操作数都是整型则执行整型运算
- 如果有一个操作数是浮点型则执行浮点型运算
需要注意,除数不能为0否则编译会报错
取余 %
在java中取余运算符是可以对小数取余的
需要注意跟除法一样,不能对0进行取余否则会报错,报错原因跟除法相同。
这里有道负数取余的例子
System.out.println(10%3);
System.out.println(10%-3);
System.out.println(-10%3);
System.out.println(-10%-3);
运行结果
解析
- 10取余3商3余1
- 10取余-3商-3余1
- -10取余3商-3余-1
- -10取余-3商3余-1
赋值及复合赋值运算符
使用方式
int a = 10;//赋值
a += 1;//等价与a=a+1;
a -= 1;//等价与a=a-1;
a *= 1;//等价与a=a*1;
a /= 1;//等价与a=a/1;
a %= 1;//等价与a=a%1;
自增自减运算符
使用方式
int a = 10;
int b = 0;
a--;//等价与a = a-1;
a++;//等价与a = a+1;
b = ++a;//前置++
b = a++;//后置++
b = --a;//后置--
b = a--;//后置++
自增自减运算符需要区分是否作为单独一条语句,或者是作为赋值语句
上面代码我们看到,两个相同的值,在做自增时,如果是后置++则先赋值然后自增,如果是前置++则先自增后赋值。
如果不取自增运算的表达式的返回值, 则前置自增和后置自增没有区别.
//单独一条语句时,此时前置和后置++等价
a++;
++a;
自减操作符同理
关系运算符
使用方式
int a = 10;
int b = 20;
System.out.println(a == b);
System.out.println(a != b);
System.out.println(a < b);
System.out.println(a > b);
System.out.println(a <= b);
System.out.println(a >= b);
注意事项
- 关系运算符的表达式返回的是boolean类型的值
- 关系表达式的等于是两个=号
逻辑运算符
短路与、短路或也称逻辑与逻辑或
逻辑与 &&
- 规则: 两个操作数都为 true, 结果为 true, 否则结果为 false.
使用方式
(表达式1) && (表达式2)
如果表达式1和表达式2都为true,则逻辑与的结果为true,否则为false
逻辑或 ||
- 规则: 两个操作数都为 false, 结果为 false, 否则结果为 true
使用方式
(表达式1) || (表达式2)
如果表达式1和表达式2都为false,则逻辑或的结果为false,否则为true
关于&& 和 || 短路求值的属性
作为"&&“和”||"操作符的操作数表达式,这些表达式在进行求值时,只要最终的结果已经可以确定是真或假,求值过程便告终止,这称之为短路求值
我们都知道, 计算 10 / 0 会导致程序抛出异常. 但是上面的代码却能正常运行, 说明 10 / 0 并没有真正被求值.
结论:
- 对于 && , 如果左侧表达式值为 false, 则表达式的整体的值一定是 false, 无需计算右侧表达式.
- 对于 ||, 如果左侧表达式值为 true, 则表达式的整体的值一定是 true, 无需计算右侧表达式.
逻辑非 !
- 规则: 操作数为 true, 结果为 false; 操作数为 false, 结果为 true(这是个单目运算符, 只有一个操作数)
使用示例
位运算符
Java 中对数据的操作的最小单位不是字节, 而是二进制位.
位操作表示 按二进制位运算. 计算机中都是使用二进制来表示数据的(01构成的序列), 按位运算就是在按照二进制位的每一位依次进行计算.
按位与 &
- 规则:如果两个二进制位都是 1, 则结果为 1, 否则结果为 0
代码示例
int a = 10;
int b = 20;
System.out.println(a & b);
运算过程
0000 0000 0000 0000 0000 0000 0000 1010 //10的二进制
0000 0000 0000 0000 0000 0000 0001 0100 //20的二进制
0000 0000 0000 0000 0000 0000 0000 0000 //按位与后 得到结果0
运算结果
按位或 |
- 规则: 如果两个二进制位都是 0, 则结果为 0, 否则结果为 1.
代码示例
int a = 10;
int b = 20;
System.out.println(a | b);
运算过程
0000 0000 0000 0000 0000 0000 0000 1010 //10的二进制
0000 0000 0000 0000 0000 0000 0001 0100 //20的二进制
0000 0000 0000 0000 0000 0000 0001 1110 //按位或后得到结果为30
运算结果
逻辑 & 和 | (不推荐使用)
- & 和 | 如果操作数为 boolean 的时候, 也表示逻辑运算. 但是和 && 以及 || 相比, 它们不支持短路求值.
代码示例
System.out.println(10 > 20 & 10 / 0 == 0); // 程序抛出异常
System.out.println(10 < 20 | 10 / 0 == 0); // 程序抛出异常
使用&当逻辑运算时,不管表达式1是否为假它都会执行表达式2。
使用 | 当逻辑运算时,不管表达式1是否为真它都会执行表达式2。
总体来说尽量不使用逻辑& 和 逻辑 | 用作逻辑运算。
按位异或 ^
- 规则:如果两个数字的二进制位相同, 则结果为 0, 相异则结果为 1.
代码示例
int a = 8;
int b = 13;
System.out.println(a ^ b);
运算过程
0000 0000 0000 0000 0000 0000 0000 1000 //8的二进制
0000 0000 0000 0000 0000 0000 0000 1101 //13的二进制
0000 0000 0000 0000 0000 0000 0000 0101 //按位异或后得到结果为5
运行结果
按位异或的4个特点
- 0异或任何数=任何数
- 1异或任何数 = 任何数取反
- 任何数异或自己 = 0
- a异或b得到c,c可以通过异或b得到a或者异或a得到b。
按位取反 ~
- 规则:如果该位为 0 则转为 1, 如果该位为 1 则转为 0
- 需要注意按位取反是对整数的补码进行取反
代码示例
int a = 2;
System.out.printf("%d\n", ~a);//打印的是原码
运算过程
0000 0000 0000 0000 0000 0000 0000 0010 //2的补码
1111 1111 1111 1111 1111 1111 1111 1101 //按位取反得到补码
1111 1111 1111 1111 1111 1111 1111 1100 //补码减一得到反码
1000 0000 0000 0000 0000 0000 0000 0011 //反码按位取反得到原码,十进制的-3
运算结果
如果有读者不清楚原码、反码、补码的话,可以去看我另一篇博客链接
移位运算
- 移位运算符有三个,都是按照补码二进制位来运算
左移位运算 <<
- 规则:二进制向左移位,二进制左边丢弃,右边补0
代码示例
int a = 10;
System.out.println(a << 1);
运算过程
运算结果
关于 << 位运算,左移一位有乘2的效果。
右移位运算 >>
- 规则:右边丢弃, 左边补符号位(正数补0, 负数补1)
代码示例
int a = 10;
System.out.println(a >> 1);
运算过程
运算结果
关于 >> 运算符,右移1位有除2的效果。
无符号右移 >>>
- 规则: 右边位丢弃, 左边位补0(不区分有没有符号)
代码示例
int a = -1;
System.out.println(a >>> 1);
运算过程
运算结果
条件运算符 :?
- 条件运算符只有一个: 表达式1 ? 表达式2 : 表达式3 当 表达式1 的值为 true 时, 整个表达式的值为表达式2的值; 当 表达式1 的值为 false 时, 整个表达式的值为 表达式3 的值
- 是 Java 中唯一的一个 三目运算符, 是条件判断语句的简化写法
代码示例
int a = 10;
int b = 20;
int max = a > b ? a : b;
System.out.println(max);
运行截图
运算符优先级
先看一段代码
System.out.println(1 + 2 * 3);
结果为 7, 说明先计算了 2*3 , 再计算 1+
另外一个例子
System.out.println(10 < 20 && 20 < 30);
此时明显是先计算的 10 < 20 和 20 < 30, 再计算 &&. 否则 20 && 20 这样的操作是语法上有误的(&& 的操作数只能是boolean).
结论
- 运算符之间是有优先级的. 具体的规则我们不必记忆. 在可能存在歧义的代码中加上括号即可.
最后附上一张运算符优先级图
运算符小结
- % 操作再 Java 中也能针对 double 来计算.
- 需要区分清楚 前置自增 和 后置自增之间的区别.
- 由于 Java 是强类型语言, 因此对于类型检查较严格, 因此像 && 之类的运算操作数必须是 boolean.
- 要区分清楚 & 和 | 什么时候是表示按位运算, 什么时候表示逻辑运算.
整体来看, Java 的运算符的基本规则和 C 语言基本一致。