变量和运算符
1 数据类型、常量、变量
1.1 常量
常量:程序运行过程中固定不变的值。
常量分类:
- 字面量:就表示直接给出的一个值(可以是整数、小数等),也有人称之为直接量。如整数常量1,2,3,小数常量3.14等。
- 使用final定义的变量(后讲)
1.2 数据类型
数据类型主要分两种数据类型:基本数据类型和引用数据类型
其中基本数据类型就是java8大基本类型:
- 整数类型:byte、short、int、long
- 小数类型:float、double
- 字符类型:char
- 布尔类型:boolean
其中我们需要记住这8大基本类型它们所占的字节(1字节=2^8)
No. | 数据类型 | 占位(字节) | 数据范围 |
---|---|---|---|
1 | byte | 1 | [-128,127] |
2 | short | 2 | [-215,215-1] |
3 | int | 4 | [正负21亿左右] |
4 | long | 8 | ..... |
5 | char | 2 | ..... |
6 | float | 4 | ..... |
7 | double | 8 | ..... |
8 | boolean | 1位 | false/true |
记住每个类型所占字节数即可
整数类型和小数类型
public class Day02Const {
public static void main(String[] args){
char a =‘中‘;
System.out.println((int)a);
//需求 输出一个整数
System.out.println(10);
System.out.println(12312312312312223L);
//在Java中,输出整数JVM默认按照int类型来输出
//输出的整数大于21亿的时候需要转换成long类型
//需求 输出一个小数
System.out.println(2.3909f);
System.out.println(2.414);
//小数类型常量JVM默认使用double类型来存储
//用float类型存储要在后面价格f/F
}
}
整型扩展:二进制0b 十进制 八进制0 十六进制0x
int i = 10; //正常十进制 输出结果为 10
int i2 = 010; //前面带0 说明是个八进制 输出结果为8
int i3 = 0x10; //前面带的0x 说明是个十六进制 输出结果为16
int i3 = 0x11; //输出结果为17
浮点数类型中:float类型又被称作为单精度类型,尾数可以精确到6-7位有效数字,在很多情况下,float类型的精度很难满足需求,所以double更常用,double表示小数的数字精度是float类型的两倍,又称为双精度,绝大部分应用程序都采用double类型。尾数可以精确到15-16位有效数字。但不论是float还是double类型在有效数字内都存在精度问题
java中输出小数时,默认选择的是double类型
浮点型扩展:在金融计算领域,以及支付领域,特别是只要涉及钱的地方都不能用浮点数类型,要用专门的BigDecimal来进行不产生舍入误差的精确数字计算。
浮点型float、double它们都有限、离散、会舍入误差、有大约、接近不相等 等特性。会导致运算结果达不到我们预期的结果。
float f = 0.1f; //0.1
double d = 1.0/10; //0.1
System.out.println(f==d); //按我们所想的话,其输出的结果应该为true 但是实际结果确实false 其原因设计内存解析的底层原理 究其原因,就是因为浮点数会有接近但不相等的特性。
//又有这个例子
float f1 = 2323123123123f;
float f2 = f1 + 1;
System.out.println(f1==f2); //按预期,怎么都不会是相等的,结果应该返回是false,但是实际结果确实true。同样设计内存底层
所以 究其各种原因得出结论:
最好完全避免使用浮点数进行比较
字符类型:在java程序中,输出是‘‘ 单引号加里面单个字符。
字符类型总结:一个字符对应一个编码表里面的一个值,得让计算机识别的话就得将输出的字符转换成二进制。所以编码表就应运而生,每个国家的字都代表一个字符同样的在编码表中会对应一个数字比如 ‘中‘在编码表中就代表20013,这是在Unicode(万国码)表中表示的位置。
其中最基础的就是Ascii码表(美国信息交换标准代码),中国的码表是GBK码表,其中每个码表都能识别Ascii码表,因为这是计算机最基础的码表,其中Java应用的码表是Unicode表(万国表)。其中Ascii码表代表一个字节,中国的GBK码表是两个字节。UTF-8等都属于码表。
尤其要记住的是:A在码表的顺序是65,a在码表的顺序是97.
布尔类型:Boolean类型只有两个值,true和false,在未来开发中用于逻辑判断。
布尔类型扩展:
boolean flag = ture;
if(flag == true){} == if(flag){}
字符串类型:字符串类型就是多个字符合在一起,使用双引号引起来。它不属于8大基本数据类型范畴里。
1.3 变量
变量是指在程序运行中,值可以发生变化的量。
定义一个变量相当于在JVM的堆空间里申请一个内存空间来存放一个相应数据类型的可变的量,其没有固定值,并且可以重复使用。
变量相当于定义一个内存区域来储存数据,同时允许修改这里面的数据,也可以获取里面的数据。
变量的声明方法
数据类型 自定义的变量名 [= 初始值];
变量的特点:
- 占据着内存中的某一块存储区域
- 该区域拥有自己的名称(变量名)和类型(数据类型)
- 可以被重复使用
- 该区域的数据可以在同一个类型范围内不断变化
变量的定义和赋值
方法一:先定义变量,然后赋值,然后再使用
例:
int a;
a = 10;
System.out.println("a");
方法二:在声明时同时赋值
int a = 10;
System.out.println("a");
变量使用的注意事项:
- 变量必须先声明,并且初始化后才能被使用。
- 定义变量必须有数据类型.
- 变量从开始定义到所在的花括号结束之内可以使用,离开花括号就不能使用了.
- 同一作用域内,变量名不能重复定义。
表达式(expression):是由数字、常量、变量、运算符、括号等组合以能求得结果的式子,表达式在开发过程中用于计算结果。
表达式举例(下列a、b、x、y、z都表示变量)
- a + b
- 3.14 + a
- (x + y) * z +100
2 基本数据类型转换
在8大基本数据类型中,boolean不属于数值类型,所以不参与转换,其他类型的转换规则如下图。一般的,byte、short、char三种类型相互之间一般不参与。
了解:为什么float占4个字节却比long占8个字节要大?
因为他们的底层实现方式不同
按照转换方式,有两种(注意:boolean类型不参与类型转换):
- 自动类型转换:范围小的数据类型直接转换成范围大的数据类型(小 ==> 大)。
- 强制类型转换:分为大的数据类型强制转换成范围小的数据类型(大 ==> 小)。
2.1 自动类型转换
自动类型转换,也称为“隐式类型转换”,就是把范围小的数据类型直接转换成范围大的数据类型。
转换规则:byte、short、char、-->int -->long --> float -->double
注意事项:byte、short、char相互之间不转换,他们参与运算首先转换成int类型
其中有个JVM优化(不是强制类型转换):范围大的常量能直接赋值给范围小的变量,只要不超过范围。
语法举例:
public class TestTypeConvert {
public static void main(Strin[] args) {
int intNum1 = 10;
long longNum2 = intNum1;
long longNum3 = 100L;
float floatNum4 = longNum3;
float floatNum5 = 31.4f;
double doubleNum6 = floatNum5;
/** 总结
* 自动类型转换 => 范围小的数据类型可以直接转换为范围大的数据类型
* long类型8字节,float类型4字节,但是float表示的数据范围比long类型大。
*/
// jvm优化:在java中,可以把范围大的常量直接赋值给范围小(byte,short,char)的变量, 只要不超过范围。
byte byteNum7 = 100;
char c = 97;
System.out.println(c);
// 错误的操作
// int intNum8 = 100;
// byte byteNum9 = intNum8;
}
}
2.2 自动类型提升
当一个算数表达式中,包含多个基本数据类型的常量或变量(boolean除外)时,整个算术表达式的结果类型将在出现自动提升,其规则是:
- 所有byte、short、char类型被自动提升到int类型,再参与运算
- 整个表达式的最终结果类型,被提升到表达式中类型最高的类型
结论:算数表达式结果的类型就是其中范围最大的数据类型。
2.3 强制类型转换
强制类型转换,也成为“显式类型转换”,就是把范围大的数据类型强制转换成范围小的数据类型。
语法格式:
范围小的数据类型 变量 = (范围小的数据类型)范围大的数据类型值;
long longNum1 = 999999;
int intNum1 = (int)longNum1;
System.out.println(intNum1);
注意:一般情况下不建议使用强转,因为强转有可能会损失精度
3. 运算符
3.1 加减乘除余
其中对于字符串而言,+符号表示连接操作,任何类型的数据和字符串相连接,结果都是字符串。
其中需要注意的就是除和余。除在java里只要没有double类型都是整除。
public class Day02Arithmetic {
public static void main(String[] args){
int num1 = 5;
int num2 = 2;
int a = num1 / num2; //结果:2
System.out.println(a);
//总结:都是整型数据相除,得到的结果也是整数,且不存在四舍五入。
double b = num1 * 1.0 /num2;
double c = num1 / num2;
System.out.println(b);
System.out.println(c);
//总结:要表达式里有double类型,输出的结果小数才会不为零。如果知识输出的是double类型,则结果还是整数结果
}
}
3.2 自增和自减
自增:++,递增操作,使变量值加1,有前置和后置之分,只能操作变量。
自减:--,递减操作,使变量值减1,有前置和后置之分,只能操作变量。
前置和后置的区别:
- 前置(++a):表示对a加1了结果过后再进行运算。例如:a=10 b=++a 就相当于a先+1 然后再运算 b+a。输出两个值的结果就是 a=11,b=11。(先增加后使用)
- 后置(a++):表示对先把a进行运算再把a+1。例如:a=10 b=a++ 就相当于先运算b+a,然后a再+1。输出两个值的结果就是 a=11,b=10。(先使用后增加)
- ++a就表示去a的地址,增加它的内容,然后把值放在寄存器中。
- a++表示取a的地址,把它的值装入寄存器,然后增加内存中的a的值。
public class Day02Arithmetic2 {
public static void main(String[] args) {
// i++ / i--: 有i++/i-- 先进行运算,然后i再+1/-1
// ++i / --i; 有++i/--i i先进行+1/-1,然后再进行运算
//情况1:
int i = 10;
i++;
System.out.println(i); //11
//情况2:
int i1 =10;
int j ;
j = i1++; //i1 = 11
int k;
k = ++i1; //i1 = 12
System.out.println("i="+i1); //12
System.out.println("j="+j); //10
System.out.println("k=" + k); //12
}
}
3.3 赋值运算符
变量 = 表达式的值或者常量值
运算符 | 运算规则 | 范例 | 结果 |
---|---|---|---|
= | 赋值 | int a=2 | 2 |
+= | 加后赋值 | int a=2,a+=2 | 4 |
*= | 乘后赋值 | int a=2,a *=2 | 4 |
-=、/=、%=与上面那种操作差不多
3.4 比较运算符
用于比较常量或变量、表达式之间的大小关系,其结果是boolean类型(要么为true,要么为false)。
其操作格式为:
boolean result = 表达式A 比较运算符 表达式B;
3.5 三元运算符
三元运算符,表示有三个元素参与的表达式,所以又称为三目运算符,其语义表示if-else(如果上面情况就做什么,否则做什么)。如果....那么...否则...
语法表达格式:
数据类型 变量 = boolean表达式 ? 结果A:结果B;
- 如果boolean表达式结果:
- 为true,则三元运算符的结果是结果A;
- 为false,则三元表达式的结果是结果B;
注:三元运算符必须定义变量接收运算的结果,否则报错
三元运算符结果的类型由结果A和结果B来决定的,结果A和结果B的类型是相同的。
例:
//需求:判断一个数99是不是偶数
public class Test{
public static void main(String[] args) {
int a = 99;
String re = (a % 2 ==0) ? "偶数":"奇数";
System.out.println(re);
}
}
3.6 逻辑运算符
逻辑运算符用于连接两个boolean表达式,结果也是boolean类型的
语法格式:
boolean result = boolean表达式A 逻辑运算符 boolean表达式B;
运算规则如下:
其中需要注意的是,短路与或 跟 与或 之间的区别:短路与或 如果在判断boolean表达式A的时候就已经确定这是个true或false的结果,就不会再执行boolean表达式b,与或 则会把整个表达式执行完。
规律:
- 非:取反,!true则为false,!false则true
- 与:有false则为false
- 或:有true则为true
- 异或:^相同则false,不同则true
& 与运算,也可以理解为“且,并”
true & true => true
true & false => false
false & true => false
false & false => false
总结 : & 运算,只要两边的表达式有一个为false,结果就为false
&& 短路与
&& 运算,只要两边的表达式有一个为false,结果就为false,如果第一个表达式为false,后续表达式不 再运算;
| 或运算,可以理解为 "或,或者"
true | true => true
true | false => true
false | true => true
false | false => false
总结 : | 运算,只要两边的表达式有一个为true,结果就为true
|| 短路或
|| 短路或运算,只要两边的表达式有一个为true,结果就为true,如果第一个表达式为true,后续表达式 不再运算;
! 非运算,可以理解为 取反
!true = false
!false = true
3.6.1 &和&&的区别
& :&左边表达式无论真假,&右边表达式都进行运算;
&& :如果&&左边表达式为真,&&右边表达式参与运算,否则&&右边表达式不参与运算,故称短路
与。
|和||区别同理。
public class Test {
public static void main(String[] args) {
//短路逻辑运算 && 和 ||
int m = 10;
int n = 20;
boolean r1 = (m > n) && (++m > 10);
System.out.println("r1 = " + r1); // false
System.out.println("m = " + m); // m = 10
}
}
3.7 运算优先级
表达式的运算都是有优先级的,基本上和数学中的优先级类似,需要注意的是,赋值运算符。
()的优先级最高,赋值运算符优先级最低
赋值运算符的运算方向是从右到左