系列连载文章,大家可以从我的专栏学习Java入门基础知识,后续也会有更高级的Java特性、企业级开发框架,也有平常工作中的技术总结和分享,欢迎关注我的CDSN博客。同时可关注微信公众号“Java开发之旅”,获得更多技术资料!
目录
闲言碎语
在上一节中,我们认识了Java中的基本数据类型(四类八种),并且定义了这些类型的变量,那么在这一节当中,我们对数据类型和变量进行更深一步的学习。
数据类型转换
上节课当中,当我们声明变量时,敢于尝试的朋友会发现以下代码也可以正常运行:
public class Hello {
public static void main(String[] args) {
//左边声明的是double双精度浮点,右边赋的值却是整数
double test = 1;
//打印是没问题的
System.out.println(test);
}
}
what???double类型不是双精度浮点的小数吗?怎么会可以存储整数呢?
是的你没有看错,确实是可以的,只不过会自动升级为小数,这就是Java当中的数据类型转换在发挥作用。
在Java当中,有些数据类型之间是可以互相兼容、互相转换的,这个机制叫做数据类型转换,就是将等号右边的数据类型转换为左边的数据类型。
一般的,大的类型可以向下兼容小的类型,此时等号右边的小类型会自动提升为左边的大类型,叫做自动转换。拿所有的数值类型来说(boolean不存在自动转换和强转,char稍后结合String讲解),在不超过各自的取值范围的情况下,自动转换关系如下图所示:
上图中的每一个数据类型,都可以兼容它右边的所有数据类型,也就是说double可以兼容所有的数据类型,float可以兼容long、int、short、byte,以此类推。
所以以下代码都是合法的(注意看注释):
public class Hello {
public static void main(String[] args) {
//声明一个byte类型变量
byte a = 1;
//将byte类型赋值给short类型,合法
short b = a;
//将short类型赋值给int类型,合法
int c = b;
//将int类型赋值给long类型,合法
long d = c;
//将long类型赋值给float类型,合法
float e = d;
//将float类型赋值给double类型,合法
double f = e;
//由于自动转换时,会提升数据类型,所以变量e的值已经不是1了,而是1.0,所以此处输出1.0
System.out.println(e);
//虽然变量f是双精度浮点,但是因为它的值是由变量e而来,所以这里其实f的值是1.00,
//只不过我们没有指定格式,Java为我们省略了最后的一个0,所以这里也输出1.0
System.out.println(f);
/*
* 以上赋值链说明,数据类型可以向下兼容,而且可以跨层级兼容
* 比如double兼容float,而float又兼容long,long又兼容int……
* 以此类推,所以double兼容所有的数值类型,其他的向下兼容同理。
* */
}
}
上面是向下兼容,如果我们要向上兼容呢?比如将一个int类型的变量赋值给short类型的变量,这就需要short兼容int,属于向上兼容。
这就需要我们手动转型,也叫做强制转换。我们只需要在值的前面用英文的小括号说明我们要转换的类型,就可以实现强制转换:
public class Hello {
public static void main(String[] args) {
int a = 1;
//使用语法进行强制转换:(转换的类型)
short b = (short) a;
System.out.println(b);
}
}
如果要将float或者double转换为整型的int、long等,会丢掉小数点后的精度:
public class Hello {
public static void main(String[] args) {
double a = 5.3;
//将浮点型转为整型
int b = (int) a;
// 输出5。
// 注意这里不是四舍五入,只是简单的丢掉小数点之后的部分,
// 就算a的值是5.9,也会输出5
System.out.println(b);
}
}
另外,前面我们说过,大类型兼容小类型会自动转换,当然我们也可以自己强制转换,只不过编辑器会提醒你不必这么做:
至于其他的强转,大家可以自由的去编写,都是一样的道理,有问题给我发私信或者在下方评论~~~
算术运算符
Java中的算术运算符主要有:
这里顺便说一句,也有人觉得+=、-=、*=、/=、%=这几个也是算术运算符,我觉得它们不能列到上面的表格中,毕竟它们只是一种简洁的变身写法,只是上面几种的变形,在下文中也会给大家介绍。
先介绍简单的加减乘除、取余:
public class Hello {
public static void main(String[] args) {
int num1 = 1;
int num2 = 2;
//加,输出3
System.out.println(num1 + num2);
//减,输出-1
System.out.println(num1 - num2);
//乘,输出2
System.out.println(num1 * num2);
//除,取商,输出0
System.out.println(num1 / num2);
//取余,输出1
System.out.println(num1 % num2);
}
}
有趣的是,算术表达式的结果,会向表达式中更高级的数据类型转型,什么意思呢?看一段代码:
什么?short类型不就是整型吗?整型进行+1操作,有毛病吗?
原因是,Java当中所有的整数,默认是int类型,就像浮点数默认是double一样。语句a = a + 1中的1,是一个整数,整数默认是int类型,虽然a是short类型,但整体的a + 1这个算术表达式的运算结果就被提升为了int。虽然结果都是整数2,但它是一个int类型的2而不是short类型的2,等号右边是int,左边是short,显然要进行强转,我这么说大家懂了吗?
所以改成以下代码即是正确的,用括号将表达式括起来,提高优先级,再强转:
再举一个例子,以下代码是正确的:
虽然表达式a = a + 1中的1是int型,但是这里的a是long类型的,最后的结果会向类型更大的转换,也就是说会自动提升为long类型,所以是可行的。
同理,以下代码就是不可行的,就像我们上面说的那样,右边的运算结果提升为了long类型,左边却是int,显然是不行的:
基于上面所说的数据类型提升,显然存在以下结论:
当算术表达式中存在浮点数时,会提升为默认的浮点类型double,特别标注的除外。
什么意思呢?看一段代码:
整型提升为浮点型,我觉得很容易理解吧,你加了一个小数,运算结果为2.6,2.6当然是浮点型了!只不过Java中默认的浮点型是double,所以提升为了double。
如果我们将小数特殊标注为float,你就可以用float类型去接收运算结果:
乘、除、取余都一个道理,不再举例了。下面重点说说++、--,即自增和自减。
有趣的++、--
++和--是自增、自减运算符,值的变化幅度是1,即自增1、自减1:
public class Hello {
public static void main(String[] args) {
int a = 0;
//自增1,等价于a = a + 1
a++;
}
}
自增和自减运算符只能直接作用于变量的身上,不能写在具体的数字身上,以下代码是错误的:
有趣的是,++、--可以写在变量的前面,也可以写在变量的后面,不同的地方有不同的执行机制,大家思考一下,以下代码的输出结果:
public class Hello {
public static void main(String[] args) {
int a= 1;
//a++
System.out.println(a++);
//++a
System.out.println(++a);
System.out.println(a);
}
}
最后的输出结果是:
为什么是1、3、3呢?这是因为,自增或自减写在变量之后,程序会先使用变量的值,再重新计算赋值;自增或自减写在变量之前,程序先重新计算赋值,再进行使用。区别就是先使用、还是先计算,++或--写在前面是先计算、再使用,写在后面是先使用、再计算。
所以上述代码,在第6行先使用变量a的值进行打印,此时的变量值是1,所以打印出了1,紧接着将变量a的值自增1,变成了2;在第8行,由于++写在了变量之前,要先进行计算、再使用,先将a的值自增1,变成了3,然后再进行打印,所以打印出了3;最后的打印语句没有自增或自减,所以也打印3。
再来一个例子:
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = ++a;
int c = a++;
System.out.println(b);
System.out.println(c);
System.out.println(a);
}
}
上述代码的打印结果是2、2、3,在第5行先将a的值+1变成2,再赋值给b,所以b的值是2;然后在第6行,先使用a的值2赋给变量c,再将a的值+1变成3,所以此时c的值是2,a的值是3,故而我们的打印结果是2、2、3,大家明白了吗?
而且,自增、自减运算符有隐式的数据类型转换,以下代码正确:
自减运算符--也是一个道理,这里我就不再举例了。
“特殊”的算术运算符
接下来就介绍几个特殊的算术运算符:+=、-=、*=、/=、%=。
它们是基本算术运算符的变形,我们就拿+=举例:
public class Hello {
public static void main(String[] args) {
int a= 1;
//意思是在a的基础上,+2
a += 2;
//输出3
System.out.println(a);
}
}
以上代码中的算术表达式a += 2,等价于a = a + 2,是一种简写而已。那么同理,a -= 2等价于a = a - 2,a *= 2等价于a = a * 2……不再举例。
需要注意的是,同自增、自减运算符一样,此类运算符也有隐式的类型转换,所以以下代码是可行的:
“+”在字符串中的应用
“+”在数值类型的计算中表示加法,它还有一种用法,就是在String类型的字符串中表示拼接:
public class Hello {
public static void main(String[] args) {
String str = "你好,";
//使用+进行拼接
str = str + "Java开发之旅";
//输出 你好,Java开发之旅
System.out.println(str);
}
}
同样的,既然“+”可以用,“+=”也可以用:
public class Hello {
public static void main(String[] args) {
String str = "你好,";
//等价于 str = str + "Java开发之旅";
str += "Java开发之旅";
//输出 你好,Java开发之旅
System.out.println(str);
}
}
而且,String类型是更大的数据类型,它可以使用“+”兼容所有的8种基本类型,表达式的结果会被提升为String字符串,注意只能是“+”进行字符串的拼接,其余的乘除减法等等都是不成立的:
public class Hello {
public static void main(String[] args) {
//输出 a的值是:1
int a = 1;
String str = "a的值是:" + a;
System.out.println(str);
//输出 b的值是:5.6
double b = 5.6;
str = "b的值是:" + b;
System.out.println(str);
//由于这里的1是字符串的“1”,所以虽然用了+=2,但只是字符串的拼接,输出字符串的“12”
str = "1";
str += 2;
System.out.println(str);
}
}
在后面我们讲到面向对象的时候,会专门用一篇文章来讲解String类,因为现在大家对类、方法、常量还没有概念,我们会逐渐深入。
算术运算符的优先级
Java当中的运算符有3种,算术运算符、关系运算符、逻辑运算符,在讲完这三种运算符之后会给大家汇总一个表。
基本的算术运算符,和我们在数学里的习惯是一样的:()、*、/、%、+、-,括号最大,往右递减之。
那+=、-=、*=……这些特殊的运算符,和基本的运算符结合起来是怎样的优先级呢?这里就留给大家思考的空间,大家下去自己尝试一下、总结一下,想想下面的执行结果:
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = a += 6 * 2 - 1;
System.out.println(b);
}
}
当然了,这里只是让大家总结,真正的开发中如果写成这样,会被同事骂死的,我们要用括号来提高优先级,这样代码的可读性也更高:
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = a += 6 * (2 - 1);
System.out.println(b);
}
}
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = (a += 6) * 2 - 1;
System.out.println(b);
}
}
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = a += (6 * 2) - 1;
System.out.println(b);
}
}
小结
以上就是第5节课的内容,你懂了吗?