打怪升级之小白的大数据之旅(三)
Java基础语法之数据类型与运算符
目录
上次回顾
上一次我们从java的环境搭建开始到我们的第一个java程序,之后,又介绍了一些java的基础语法: 注释,关键字,标识符,变量,常量以及数据存储的底层逻辑以及二进制的相互转换
今天,我们来探讨一下java的数据类型他们之间的相互转换,最后就是运算符,就像一个孩童刚开始学走路,我们需要了解清楚身体的组件,各个部位的功能,之后才可以自由的飞奔~
数据类型
首先说说java数据类型的基本概念:
Java是一种强类型的语言,针对每一种数据都定义了数据类型,不同类型的数据二进制表示方式或分配的空间大小有所不同,java数据类型主要分为两大类:(定义变量需要确定数据类型,即确定数据使用的空间大小和二进制表示形式)
通俗一点来讲, 计算机它自己是不知道数据的类型的,因为它只知道01,而我们人类世界地大物博,色彩缤纷,所以需要告诉计算机我们的世界对不同事物的定义~在Java的世界中,分为两大数据类型,分别是基本数据类型和引用数据类型;它们在计算机的内存中,分别会存储在堆内存和栈内存中(这里后面会介绍到),引用数据类型,我们会在面向对象中详细介绍
基本数据类型(四类八种):
四大类:
- 整数
整数根据取值范围不同,又分为四个小类, byte short int 和long
默认是int类型,如果要使用long类型,需要在后面添加 L
示例代码:/* 整数类型的定义 */ // byte 类型 byte byteNum = 1; // short 类型 short shortNum = 19; // int 类型 int intNum = 999; // long 类型 long longNUM = 12345678L;
注意: 假设我们定义的整数类型,它的值超过了本身的范围,就会造成编译错误,因此我们定义这个变量的时候要想好了~
- 浮点数(小数)
默认是doubel类型,如果定义float,建议后面添加 F/* 浮点数数类型的定义,建议后面添加F,这样更加便于后期阅读 */ // float类型 byte floatNum = 1.1F; // doubel类型 short doubelNum = 19.9999;
- 字符(java定义中,使用的是单引号'')
/* 字符类型的定义 */ // char 类型, 一定是单引号!! char charVar = 'a';
- 布尔
布尔类型只有两个值 true和false, 它在关键字那里提到过,它是特殊值,我们一定不要使用它用来做变量名哈~/* 布尔类型的定义 */ // boloean类型 boloean booleanVar = true; // short 类型 boloean booleanVar2 = false;
四大基本数据类型讲完了,引用数据类型提一下,有个印象,后面详细讲到的时候就不会觉得突兀,他们分别是: 类、数组、接口 字符串,
数据类型的转换
这里的数据类型转换,仅限于基本数据类型,而且不包括布尔类型,因为它是特殊值嘛`~
首先,看下面这张图:
数据类型分类两种,一种是自动转换,一种是强制转换(手动)
自动类型转换(自动类型提升)
为什么这么分类,有什么作用呢?就拿上图来说,
上图是基本数据类型按照取值范围从小到大的关系,当我们进行不同类型之间的运算时,就需要进行类型转换
比如byte类型,它的取值范围只是-128~127,超过范围,它该怎么办?当然是求抱大腿啊,所以,自动抱大腿的类型转换就分为以下几种情况:
- 当把存储范围小的值(常量值、变量的值、表达式计算的结果值)赋值给了存储范围大的变量时
//char自动升级为int int i = 'A'; //int自动升级为double double d = 10;
- 当存储范围小的数据类型与存储范围大的数据类型一起混合运算时,会按照其中最大的类型运算
int i = 1; byte b = 1; double d = 1.0; double sum = i + b + d;//混合运算,升级为double
- 当byte,short,char数据类型进行算术运算时,按照int类型处理
byte b1 = 1; byte b2 = 2; byte b3 = b1 + b2;//编译报错,b1 + b2自动升级为int char c1 = '0'; char c2 = 'A'; System.out.println(c1 + c2);//113
强制转换
- 从数据范围大的类型转换为数值范围小的类型
- 将取值范围大的类型转换成取值范围小的类型时需要进行强制(显示)类型转换。
例如:
1). 将小数1.5 赋值到int 类型变量会发生什么?产生编译失败,肯定无法赋值。
int i = 1.5; // 错误
2). 想要赋值成功,只有通过强制类型转换,将double 类型强制转换成int 类型才能赋值
强制转换的格式:
数据类型 变量名 = (数据类型)被强转数据值
int i = (int)3.14;//强制类型转换,损失精度
double d = 1.2;
int num = (int)d;//损失精度
int i = 200;
byte b = (byte)i;//溢出
// 当某个值想要提升数据类型时,也可以使用强制类型转换
int i = 1;
int j = 2;
double shang = (double)i/j;
注意事项:强制类型转换,有可能损失精度,慎重转换
运算符
当我们知道数据类型后,肯定就需要对变量做一些运算,比如我需要了解这个月赚了多少钱,那么,我需要先知道每天赚多少,总共工作了多少天,就需要用到乘法,就会用到算数运算符---> 日薪*工作时间
人是社会动物,免不了攀比,当然需要比较一下,比较运算符闪亮登场: 我女朋友比老王家的女朋友好看贤惠!---> 我的女朋友好看贤惠程度>老王家女朋友(虽然我是单身~~),
我写博客的时候,为了轻松愉快的码字,此时的我就需要一边码字,一边听歌,就需要逻辑运算符---> 一边听歌&&一边码字 可以轻松的完成我的博客~
好了,就暂时举几个简单的例子,具体的运算符我制作了一个表格:
运算符的分类,按照功能划分:
分类 | 运算符 |
算术运算符 | +、-、*、/、%、++、-- |
赋值运算符 | =、+=、-=、*=、/=、%=等 |
关系运算符 | >、>=、<、<=、==、!= |
逻辑运算符 | &、|、^、!、&&、|| |
条件运算符 | (条件表达式)?结果1:结果2; |
位运算符(了解) | &、|、~、^、<<、>>、>>> |
也可以按照操作数来划分:
分类 | 运算符 | 示例 |
一元(单目)运算符 | ++、--、! | i++、--i |
二元(双目)运算符 | +、-、*、/、%、>、<=等 | a+b、10>=9 |
三元(三目)运算符 | 表达式1?表达式2:表达式3 | age>=18?"成年":"未成年" |
下面,我来一一介绍一下
算数运算符:
算数运算符 | 符号注解 |
+ | 加法运算,字符串连接运算,正号 |
- | 减法运算,负号 |
* | 乘法运算 |
/ | 除法运算,整数/整数结果还是整数 |
% | 求余运算,余数的符号只看被除数 |
++ | 自增运算 |
-- | 自减运算 |
注意事项: | ++ -- 分类 前自增/减和后自增/减 |
示例代码:
- 加减乘除取余
public class OperatorDemo01 {
public static void main(String[] args) {
int a = 3;
int b = 4;
System.out.println(a + b);// 7
System.out.println(a - b);// -1
System.out.println(a * b);// 12
System.out.println(a / b);// 计算机结果是0,为什么不是0.75呢?
System.out.println(a % b);// 3
System.out.println(5%2);//1
System.out.println(5%-2);//1
System.out.println(-5%2);//-1
System.out.println(-5%-2);//-1
//商*除数 + 余数 = 被除数
//5%-2 ==>商是-2,余数时1 (-2)*(-2)+1 = 5
//-5%2 ==>商是-2,余数是-1 (-2)*2+(-1) = -4-1=-5
}
}
- ""+""号的用法
- 第一种:对于""+""号,两边都是数值,那么它就是加法的意思
- 第二种:对于""+""号两边,至少有一边是字符串的话,+就是拼接字符串的意思,无论什么类型,与字符串拼接,结果都是字符串
public class OperatorDemo02 { public static void main(String[] args) { // 字符串类型的变量基本使用 // 数据类型 变量名称 = 数据值; String str1 = "Hello"; System.out.println(str1); // Hello System.out.println("Hello" + "World"); // HelloWorld String str2 = "Java"; // String + int --> String System.out.println(str2 + 520); // Java520 // String + int + int // String + int // String System.out.println(str2 + 5 + 20); // Java520 } }
-
自增自减运算,这里是一个难点
-
++运算,变量自己的值加1,- -运算,变量自己的值减一,下面我举例子就用++来举例了
-
++运算分类以下两种情况
-
单独使用
单独使用时,变量的前++和后++,变量值是一样的,用谁都可以
变量前++: ++a
变量后++: a++ -
复合使用
和其他变量放在一起使用或者和输出语句放在一起使用,前++和后++就产生了不同
变量前++ :变量先自身加1,然后再取值。
变量后++ :变量先取值,然后再自身加1
示例代码:public class OperatorDemo03 { public static void main(String[] args) { // 其他变量放在一起使用 int x = 3; //int y = ++x; // y的值是4,x的值是4, int y = x++; // y的值是3,x的值是4 System.out.println(x); System.out.println(y); System.out.println("=========="); // 和输出语句一起 int z = 5; //System.out.println(++z);// 输出结果是6,z的值也是6 System.out.println(z++);// 输出结果是5,z的值是6 System.out.println(z); int a = 1; a = a++;//(1)先取a的值“1”放操作数栈(2)a再自增,a=2(3)再把操作数栈中的"1"赋值给a,a=1 int i = 1; int j = i++ + ++i * i++; /* 从左往右加载 (1)先算i++ ①取i的值“1”放操作数栈 ②i再自增 i=2 (2)再算++i ①i先自增 i=3 ②再取i的值“3”放操作数栈 (3)再算i++ ①取i的值“3”放操作数栈 ②i再自增 i=4 (4)先算乘法 用操作数栈中3 * 3 = 9,并把9压会操作数栈 (5)再算求和 用操作数栈中的 1 + 9 = 10 (6)最后算赋值 j = 10 */ } }
-
-
赋值运算符:
赋值运算符 | 符号解释 |
= | 将符号右边的值,赋值给左边的变量 |
+= | 将符号左边的值和右边的值进行相加操作,最后将结果赋值给左边的变量 |
-= | 将符号左边的值和右边的值进行相减操作,最后将结果赋值给左边的变量 |
*= | 将符号左边的值和右边的值进行相乘操作,最后将结果赋值给左边的变量 |
/= | 将符号左边的值和右边的值进行相除操作,最后将结果赋值给左边的变量 |
%= | 将符号左边的值和右边的值进行取余操作,最后将结果赋值给左边的变量 |
注: | 所有的赋值运算符的=左边一定是一个变量 |
赋值,比较运算符,关系运算符都比较简单,我直接上示例代码:
public class OperatorDemo04 {
public static void main(String[] args) {
int a = 3;
int b = 4;
a = a + b;
System.out.println(a); // 7
System.out.println(b); // 4
}
}
public class OperatorDemo04 {
public static void main(String[] args) {
int a = 3;
int b = 4;
b += a;// 相当于 b = b + a ;
System.out.println(a); // 3
System.out.println(b); // 7
short s = 3;
// s = s + 4; 代码编译报错,因为将int类型的结果赋值给short类型的变量s时,可能损失精度
s += 4; // 代码没有报错
//因为在得到int类型的结果后,JVM自动完成一步强制类型转换,将int类型强转成short
System.out.println(s);
int j = 1;
j += ++j * j++;//相当于 j = j + (++j * j++);
System.out.println(j);//5
}
}
比较/关系运算符:
关系运算符 | 符号解释 |
< | 比较符号左边的数据是否小于右边的数据,如果小于结果是true。 |
> | 比较符号左边的数据是否大于右边的数据,如果大于结果是true。 |
<= | 比较符号左边的数据是否小于或者等于右边的数据,如果大于结果是false。 |
>= | 比较符号左边的数据是否大于或者等于右边的数据,如果小于结果是false。 |
== | 比较符号两边数据是否相等,相等结果是true。 |
!= | 不等于符号 ,如果符号两边的数据不相等,结果是true。 |
注: | 比较运算符,是两个数据之间进行比较的运算,运算结果一定是boolean值true或者false |
示例代码:
public class OperatorDemo05 {
public static void main(String[] args) {
int a = 3;
int b = 4;
System.out.println(a < b); // true
System.out.println(a > b); // false
System.out.println(a <= b); // true
System.out.println(a >= b); // false
System.out.println(a == b); // false
System.out.println(a != b); // true
}
}
逻辑运算符:
逻辑运算符 | 符号解释 | 符号特点 |
& | 与,且 | 有false则false |
| | 或 | 有true则true |
^ | 异或 | 相同为false,不同为true |
! | 非 | 非false则true,非true则false |
&& | 双与,短路与 | 左边为false,则右边就不看 |
|| | 双或,短路或 | 左边为true,则右边就不看 |
逻辑运算符这里,着重提一下逻辑与&,逻辑或|,短路与&&,短路或||的区别:
短路与,短路或运算符左边表达式结果可以确定最终结果,则运算符右边表达式不再进行运算,效率高
- &&与&的区别
&&和&结果一样,&&有短路效果,左边为false,右边不执行;&左边无论是什么,右边都会执行 - ||与|的区别
||和|结果一样,||有短路效果,左边为true,右边不执行;|左边无论是什么,右边都会执行。
示例代码:
public class OperatorDemo06 {
public static void main(String[] args) {
int a = 3;
int b = 4;
int c = 5;
// & 与,且;有false则false
System.out.println((a > b) & (a > c));
System.out.println((a > b) & (a < c));
System.out.println((a < b) & (a > c));
System.out.println((a < b) & (a < c));
System.out.println("===============");
// | 或;有true则true
System.out.println((a > b) | (a > c));
System.out.println((a > b) | (a < c));
System.out.println((a < b) | (a > c));
System.out.println((a < b) | (a < c));
System.out.println("===============");
// ^ 异或;相同为false,不同为true
System.out.println((a > b) ^ (a > c));
System.out.println((a > b) ^ (a < c));
System.out.println((a < b) ^ (a > c));
System.out.println((a < b) ^ (a < c));
System.out.println("===============");
// ! 非;非false则true,非true则false
System.out.println(!false);
System.out.println(!true);
}
}
条件运算符:
条件运算符格式 |
条件表达式?结果1:结果2 |
条件运算符计算方式:
|
示例代码:
public static void main(String[] args) {
int i = (1==2 ? 100 : 200);
System.out.println(i);//200
int j = (3<=4 ? 500 : 600);
System.out.println(j);//500
}
位运算符:
位运算符 | 符号解释 |
& | 按位与,当两位相同时为1时才返回1 |
| | 按位或,只要有一位为1即可返回1 |
~ | 按位非,将操作数的每个位(包括符号位)全部取反 |
^ | 按位异或。当两位相同时返回0,不同时返回1 |
<< | 左移运算符 |
>> | 右移运算符 |
>>> | 无符号右移运算符 |
位运算符这里不是很好理解,需要各位看官耐心看完,它们的值是负数的时候,位运算会多一些操作:
- 位运算符的运算过程都是基于补码运算,但是看结果,我们得换成原码,再换成十进制看结果
- 从二进制到十进制都是基于原码
- 位运算直接对二进制进行位移操作实现数值运算,所以运算效率高
- 如果操作数是boolean类型,就是逻辑运算符,如果操作数是整数,那么就是位运算符
- 左移 <<
-
运算规则:左移几位就相当于乘以2的几次方
注意:当左移的位数n超过该数据类型的总位数时,相当于左移(n-总位数)位
byte,short,char在计算时按照int类型处理 -
示例:
3<<4 类似于 3*2的4次= 3*16 = 48
-3<<4 类似于 -3*2的4次= -3*16 = -48
-
- 右移>>
- 运算规则:类似于除以2的n次,如果不能整除,向下取整
- 示例:
69>>4 类似于 69/2的4次 = 69/16 =4
-69>>4 类似于 -69/2的4次 = -69/16 = -5
- 无符号右移>>>
- 运算规则: 往右移动后,左边空出来的位直接补0,不看符号位
正数:和右移一样
负数:右边移出去几位,左边补几个0,结果变为正数 - 示例:
69>>>4 类似于 69/2的4次 = 69/16 =4
-69>>>4 结果:268435451
- 运算规则: 往右移动后,左边空出来的位直接补0,不看符号位
-
按位与: &
-
运算规则: 对应位都是1才为1
1 & 1 结果为1
1 & 0 结果为0
0 & 1 结果为0
0 & 0 结果为0 -
示例:
9&7 = 1
-
-
按位或: |
-
运算规则:对应位只要有1即为1
1 | 1 结果为1
1 | 0 结果为1
0 | 1 结果为1
0 & 0 结果为0 -
示例:
9|7 结果: 15
-9|7 结果: -9
-
-
按位异或: ^
-
运算规则:对应位一个为1一个为0,才为1
1 ^ 1 结果为0
0 ^ 1 结果为1
0 ^ 0 结果为0 -
示例:
9^7 结果为14
-9^7 结果为-16
-
-
按位取反: ~
-
运算规则:~0就是1 , ~1就是0
-
示例:
~9 结果:-10
~-9 结果:8
-
知道了这么多运算符,当我们在参与复合运算时,怎么知道谁先谁后呢?就跟数学运算有先乘除,后加减这个法则一样,Java运算符也有自己的优先级:
运算符的优先级
位运算符 | 符号解释 |
& | 按位与,当两位相同时为1时才返回1 |
| | 按位或,只要有一位为1即可返回1 |
~ | 按位非,将操作数的每个位(包括符号位)全部取反 |
^ | 按位异或。当两位相同时返回0,不同时返回1 |
<< | 左移运算符 |
>> | 右移运算符 |
>>> | 无符号右移运算符 |
提示说明:
(1)表达式不要太复杂
(2)先算的使用()
大体的排序:算术 > 位 > 比较 > 逻辑 > 三元 > 赋值
总结
本章着重介绍了数据类型、类型转换和运算符,位运算符比较晦涩一些,大家只需要了解并会使用 左移<< 与 右移>>就好, java的很多源码,都用到了位运算符,大家有个印象即可,好啦,今天内容就这么多,希望各位看官有所收获~