进制
1、计算机世界中只有二进制。
那么在计算机中存储和运算的所有数据都要转为二进制。
包括数字、字符、图片、声音、视频等。
2、计算机中的存储单位
(1)最小单位是比特(bit),即一位二进制值,要么0要么是1
(2)最基本单位是字节(byte),(1字节 = 8位)(1byte = 8bit)
1024byte = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB
1024TB = 1PB
…
10月24日是程序员节。
很多硬件厂商的换算单位。1000byte=1KB。
网络带宽:100Mb 这个b是bit。
100Mb = 100/8MB
3、 八种基本数据类型
(1)byte:字节类型,占1个字节,占8位,-128~127
(2)short:短整型,占2个字节,占16位,-32768~32767
(3)int:整型,占4个字节,占32位,-2的31次方~2的31次方-1
(4)long:长整型,占8给字节,占64位,-2的63次方~2的63次方-1
(5)float:单精度浮点型,占4个字节,占32位
(6)double:双精度浮点型,占8个字节,占64位
(7)char:字符型,占2个字节,而且无符号,0~65535
(8)boolean:布尔型,在实际中用1表示true,0表示false。只需要1位就够了。
4、如何存储?
规定
(1)为了数据的存储和运算的简便处理,计算机世界中发明了原码、反码、补码的概念。
本质上,计算机世界中只有补码。原码、反码是认为为了换算和理解补码提出的概念。
(2)最高位是符号位
1表示负数
0表示正数
(3)正数三码合一:原码、反码、补码都一样
负数三码不同:
负数的原码:最高位是1,其余位数它的绝对值的二进制值
负数的反码:最高位不变,其余位数在原码基础上取反(0变1,1变0)
负数的补码:在反码的基础上 加 1
例如:
正数:25 二进制:11001
如果25是byte类型,完整的二进制 00011001
如果25是int类型,完整的二进制 0000 0000 0000 0000 0000 0000 0001 1001
负数:-25
以byte为例
负数的原码:10011001
负数的反码:11100110
负数的补码:11100111
5、为什么byte类型是-128~127?
byte类型是8位。
正数的范围:
0000 0001: 1
0111 1111:127
中间的0:
0000 0000 :0 用它表示0
1000 0000 : 0 不用它表示0,用它来表示别的
负数的范围:
1000 0001:-127
补码:1000 0001
反码:1000 0000
原码:1111 1111
1111 1111:-1
补码:1111 1111
反码:1111 1110
原码:1000 0001
-127 -1 = -127 + (-1)= 1000 0001 + 1111 1111 = 1 1000 0000 = -128
但是byte只能表示8位,最左边的截掉,剩下的是 1000 0000 ,就用它来表示-128。
6、float和double如何存储?
(1)小数如何变为二进制?(了解)
整数部分:除2倒取余
小数部分:乘2取整数部分
小数的存储分为三个部分:
①符号位
②指数位:float有8位指数位 255次 结论1:因为指数的增长非常快,float的4个字节比long类型的8个字节数据范围大。
double有11位指数位 n次
③尾数:float有23位
double有52位 结论2:double比float的精度范围大
有的小数在转为二进制时,会出现*2一直循环或者超过float和double的尾数范围。
结论3:float和double是浮点类型,不是定点类型,即不精确。
7、char类型是如何存储的?
Java中char类型的字符,使用Unicode字符集,将所有的字符进行编码。
每一个字符都一个唯一的Unicode编码值。
例如:
a:97 b:98
A:65 B:66
0:48 1:49
…
计算机早期只能表示128个字符,ASCII码表。
Unicode字符集兼容ASCII码表。
数据类型的转换
(1)基本数据类型的转换
(2)引用数据类型的转换(今天不讨论它)
一、基本数据类型的转换
1、自动类型转换
(1)当我们把存储范围小的类型的值/变量/表达式的结果赋值给存储范围大的类型的变量
例如:int num = ‘男’; 把char类型值赋值给int类型的变量num
(2)当byte与byte,short与short,char与char,或者它们三个之间的运算,都会自动升级为int
(3)当很多种基本数据类型的值一起混合运算时,结果是升级为它们当中最大的类型。
(4)boolean不参与数据类型转换
2、强制类型转换
格式:
(强制为xx类型)变量或值或(表达式)
(1)当我们把存储范围大的类型的值/变量/表达式的结果赋值给存储范围小的类型的变量
例如:int num = 97;
char c = (char)num;
注意:这种情况的强制是有风险:可能溢出或损失精度
(2)当我们需要强制“提升”某个变量或值的数据类型时,也可以使用强制类型转换
这种情况不会溢出后损失精度,只是类型转换
(3)boolean不参与数据类型转换
3、特殊的类型String
凡是与字符串进行“+”拼接运算,结果就是字符串。
class Test{
public static void main(String[] args){
//左边num是int,右边的'男'是char类型
//自动类型转换
int num = '男';
System.out.println(num);//30007
//强制类型转换
char gender = (char)num;
System.out.println(gender);//男
//自动类型转换
long bigNum = 1234567L;
float f = bigNum;
System.out.println(f);//1234567.0
byte b1 = 1;
byte b2 = 2;
//byte b3 = b1 + b2;
byte b3 = (byte)(b1 + b2);
System.out.println("b3 = " + b3);
short s1 = 1;
short s2 = 2;
//short s3 = s1 + s2;
char c1 = '0';
char c2 = '1';
//char c3 = c1 + c2;
//char c3 = b1 + s1;
double d = 1.0;
double sum = b1 + s1 + c1 + bigNum + f + d;
int a = 1;
int b = 2;
//double result = 1/2;//0.0
double result = (double)a/b;//0.5 把a强制为double类型
System.out.println("result = " + result);
int i = 130;
byte j = (byte)i;//-126
System.out.println("j = " + j);
double price = 34.67;
int p = (int)price;
System.out.println("p = " + p);
//字符串的拼接
String str = "hello" + 1;
System.out.println("str = " + str);
System.out.println('a' + 'b' + "=");//195=
System.out.println("=" + 'a' + 'b' );//=ab
System.out.println('a' + "=" + 'b' );//a=b
}
}
进制的表示
十进制:正常表示
二进制:在数字前面加0B或0b
八进制:在数字前面加0
十六进制:在数字前面加0X或0x
运算符
一、算术运算符
加:+
(1)如果是基本数据类型相加 表示求和
(2)如果是与字符串进行相加 表示拼接
减:-
乘:*
除:/
如果两个整数相除,结果只保留整数部分
模(取余):%
余数的正负号,只看被除数,被模数
被除数 / 除数 = 商 .... 余数
被除数 = 商 * 除数 + 余数
被除数(-5) / 除数(-2) = 商(2)....余数(-1)
被除数(-5) = 除数(-2) * 商(2) + 余数(-1) = -4 - 1= -5
正号:+
负号:-
自增:++
某个变量的值自增1
自减:–
某个变量的值自减1
如果自增自减变量单独运算,++/–在前还是在后,都一样;
如果自增自减变量与其他变量一起运算,++/–在前,先自增/自减然后再取自增变量的值去参与其他运算;
++/–在前,先取自增变量的值放到操作数栈中,然后紧接着做自增/自减,然后再运算其他的;
Arithmetic:算术
class Arithmetic{
public static void main(String[] args){
System.out.println(1 + 2);
System.out.println(1 - 2);
System.out.println(1 * 2);
System.out.println(1 / 2);
System.out.println(1 % 2);
System.out.println("---------------------------");
System.out.println(5 / 2);//2
System.out.println(-5 / -2);//2
System.out.println(-5 / 2);//-2
System.out.println(5 / -2);//-2
System.out.println("---------------------------");
System.out.println(1 % 2);//1
System.out.println(-1 % -2);//-1
System.out.println(-1 % 2);//-1
System.out.println(1 % -2);//1
System.out.println("---------------------------");
int a = 5;
int b = -a;
int c = +b;
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("---------------------------");
int i = 0;
i++; //自增1 i=1
++i; //自增1 i=2
System.out.println("i = " + i);
System.out.println("---------------------------");
i = 0;
int j = ++i;//(1)i先自增变为1(2)然后取出i的值,放到“操作数栈”的位置(3)赋值给j
System.out.println("i = " + i);
System.out.println("j = " + j);
System.out.println("---------------------------");
i = 0;
int k = i++;//(1)先取出i的值0,放到“操作数栈”的位置(2)然后i自增(3)赋值给j
System.out.println("i = " + i);
System.out.println("k = " + k);
System.out.println("---------------------------");
int m = 0;
m = ++m;//(1)先m自增(2)再取m的值1,放到“操作数栈”的位置(3)在把“操作数栈”的值赋值给m
System.out.println("m = " + m);//m=1
System.out.println("---------------------------");
int n = 0;
n = n++;//(1)先取n的值0,放到“操作数栈”的位置(2)n自增n=1(3)在把“操作数栈”的值0赋值给n
System.out.println("n = " + n);//n=0
System.out.println("---------------------------");
int x = 1;
int y = ++x * x++ + x++;
/*
(1)++x
A:先x自增 x = 2
B:取x的值2,放到“操作数栈”
(2)x++
A:先取x的值2,放到“操作数栈”
B:x自增 x=3
(3)取出“操作数栈”的两个值,2*2=4,重新放回“操作数栈”
(4)x++
A:先取x的值3,放到“操作数栈”
B:x自增
(5)取出“操作数栈”的两个值,4+3=7,重新放回“操作数栈”
(6)取出“操作数栈”的结果,赋值给y
*/
System.out.println("x = " + x);
System.out.println("y = " + y);
System.out.println("---------------------------");
int p = 1;
int q = ++p + p++ * ++p;
/*
(1)++p
A:先自增 p =2
B:再取p的值2,放到“操作数栈”
(2)p++ * ++p中先算
①p++
A:先取p的值2,放到“操作数栈”
B:p自增 p=3
②++p
A:先自增 p =4
B:再取p的值4,放到“操作数栈”
③乘法 2*4=8
(3)求和 2 + 8 = 10
*/
System.out.println("p = " + p);
System.out.println("q = " + q);
}
}
二、赋值运算符
1、最基本的赋值运算符:=
运算的特点:
(1)永远是把=右边的xx赋值给=左边的变量
==> =左边一定是一个变量
(2)左边变量的类型,与右边的值的类型,要么一致或者兼容
一致:一样
兼容:可以同自动类型转换进行升级
(3)赋值一定是最后算的
2、扩展的赋值运算符
+=
-=
*=
/=
%=
…
中间不允许有空格
运算的特点:
(1)把 扩展的赋值运算符 左边的变量 与 右边的值/表达式再继续xx运算,结果赋值给左边的变量
(2)如果最后运算的结果的类型超过左边变量的类型,会发生自行发生强制类型转换
即要注意可能发生溢出或损失精度
Assign:委派,赋值
class AssignOperator{
public static void main(String[] args){
int x = 1;
int y = 2;
//x + y = 3;//错误的 左边x + y是一个表达式,不是变量
int z = x + y; //左右两边的类型一样
double d = 1; //左边是double,右边是int,int赋值给double是允许,可以自动类型转换
int i = 1;
i += 2; //等价于 i= i+2;
System.out.println("i = " + i);//3
int j = 3;
j *= i + j;//等价于 j = j * (i+j);
System.out.println("j = " + j);
byte b1 = 127;
byte b2 = 2;
//b1 = b1 + b2;//右边是int,左边是byte
b1 += b2;//等价于 b1 = (byte)(b1 + b2);
System.out.println("b1 = " + b1);
}
}
三、比较运算符
1、比较运算符的类型
大于:>
小于:<
大于等于:>=
小于等于:<=
等于:==
注意:与赋值运算符=的区别
不等于:!=
2、比较运算符的运行结果:true/false
3、比较运算符中的>,<,>=,<=
只支持:整型、浮点型、字符型,不支持boolean,也不支持String等引用数据类型。
对于比较运算符中的==和!=是支持所有类型的
class Compare{
public static void main(String[] args){
System.out.println(3 > 2);
System.out.println(3 < 2);
System.out.println(3 == 2);
//System.out.println(3 = 2);//错误
int a = 3;
int b = 2;
System.out.println(a = b);//把b中的值赋值给a,并显示a变量的值
System.out.println("a = " + a);
System.out.println("b = " + b);
int age = 20;
//判断这个age是否在[18,28]之间
//System.out.println(18 <= age <= 28);//错误 18 <= age结果要么是true要么false,是boolean
//System.out.println("hello" > "world");
//System.out.println("hello" == "world");//可以,比较的是对象的地址
int num = 10;
double d = 10.0;
System.out.println(num == d);//true 会发生自动类型转换
}
}
四、逻辑运算符
1、逻辑运算符的类型:
逻辑与:&
只有左右两边都为true,结果才为true。
逻辑或:|
只要左右两边有一个为true,结果就为true。
逻辑非:!
取反,!true为false,!false为true
逻辑异或:^
只有当左右两边一个为true一个为false,结果才为true。
短路与:&&
只有左右两边都为true,结果才为true。
短路或:||
只要左右两边有一个为true,结果就为true。
2、特点
(1)逻辑运算符的左右两边必须是boolean类型
(2)逻辑运算符的运算结果还是boolean类型
3、逻辑与 和 短路与之间的区别
对于短路与&&,如果&&左边是false时,右边是不算的。
因为左边是false时,右边无论结果怎么样,最终都是false。
对于逻辑与&,不管左边是true还是false,右边都要计算。
同理
4、逻辑或 和 短路或之间的区别
对于短路或||,如果||左边是true时,右边就不算了。
对于逻辑或|,不管左边是true还是false,右边都要计算。
实际开发中,基本上使用短路&&和||,效率更高。
class LogicOperator{
public static void main(String[] args){
System.out.println(true & true);
System.out.println(true & false);
System.out.println(false & true);
System.out.println(false & false);
System.out.println("======================");
System.out.println(true | true);
System.out.println(true | false);
System.out.println(false | true);
System.out.println(false | false);
System.out.println("======================");
System.out.println(true ^ true);
System.out.println(true ^ false);
System.out.println(false ^ true);
System.out.println(false ^ false);
System.out.println("======================");
System.out.println(true && true);
System.out.println(true && false);
System.out.println(false && true);
System.out.println(false && false);
System.out.println("======================");
System.out.println(true || true);
System.out.println(true || false);
System.out.println(false || true);
System.out.println(false || false);
System.out.println("======================");
System.out.println(!true);
System.out.println(!false);
System.out.println("======================");
int i = 1;
System.out.println(i<0 & ++i > 1);
System.out.println("i = " + i);
System.out.println("======================");
int j = 1;
System.out.println(j<0 && ++j > 1);
System.out.println("j = " + j);
System.out.println("======================");
int age = 20;
//判断这个age是否在[18,28]之间
System.out.println(18 <= age && age<=28);
}
}
五、条件运算符
1、格式
条件表达式/布尔值 ? 结果表达式1/结果值1 : 结果表达式2/结果值2
2、运算规则
如果 “条件表达式/布尔值"的结果是true,那么整个表达式的结果就取 ”结果表达式1/结果值1"的值,否则就取“结果表达式2/结果值2”的值
运算符的分类:
按照功能分:算术运算符、赋值运算符、比较运算符、逻辑运算、条件运算符…
按照操作数个数分:一元运算符(单目运算符)、二元运算符(双目运算符)、三元运算符 (三目运算符)
一元运算符:操作数只有一个
例如:正号(+) +a
负号(-) -a
自增自减 ++i i++
逻辑非: !true
二元运算符:操作数有两个
例如:加法:a+b
减法:a-b
大于:a>b
逻辑与:a&b
三元运算符:条件 ? 结果1 : 结果2
class ConditionOperator{
public static void main(String[] args){
boolean marry = true;
System.out.println(marry ? "已婚" : "未婚");
marry = false;
System.out.println(marry ? "已婚" : "未婚");
//找两个整数中的最大值
int a = 1;
int b = 2;
System.out.println("最大值是:" + (a>=b ? a : b));
//找出三个数中的最大值
int x = 1;
int y = 2;
int z = 0;
//如果x>=y成立,把x的值赋值给max,否则把y的值赋值给max
int max = x>=y ? x : y;
max = max >= z ? max : z;
System.out.println("最大值是:" + max);
}
}
六、位运算符
1、位运算符的类型
(1)左移:<<
左移几位,相当于乘以2的几次方
(2)右移:>>
右移几位,相当于除以2的几次方,如果不能整除往下取整
(3)无符号右移:>>>
对于正数来说,没区别
对于负数来说,无符号右移之后,左边是补0,所以会导致负数变为正数
(4)按位与:&
两个数对应的位,1&1为1,1&0为0,0&1为0,0&0为0(有0则0)
(5)按位或:|
两个数对应的位,1|1为1,1|0为1,0|1为1,0|0为0(有1则1)
(6)按位异或:^
两个数对应的位,1 ^ 1为0,1 ^ 0为1,0 ^ 1为1,0 ^ 0为0(相同为0,不同为1)
(7)按位取反
原来位是1变为0,0变为1
2、位运算符的特点
(1)要求操作数必须是整型
(2)位运算符是在值的补码形式上进行计算的
(3)阅读性不是很强,因为人不能一眼看到结果,
但是它的效率是非常高。
class Bit{
public static void main(String[] args){
double d = 1.2;
//System.out.println(d >>2);//错误,操作数类型错
System.out.println(1 << 4);//16
/*
1的补码:0000 0000 0000 0000 0000 0000 0000 0001
1<<4: 0000 0000 0000 0000 0000 0000 0001 0000
*/
System.out.println(10 << 4);//160
/*
10的补码:0000 0000 0000 0000 0000 0000 0000 1010
10<<4: 0000 0000 0000 0000 0000 0000 1010 0000
*/
System.out.println(125 >> 4);//7
/*
125的补码:0000 0000 0000 0000 0000 0000 0111 1101
125>>4: 0000 0000 0000 0000 0000 0000 0000 0111
*/
System.out.println(-125 >> 4);//-8
/*
-125的原码:1000 0000 0000 0000 0000 0000 0111 1101
-125的反码:1111 1111 1111 1111 1111 1111 1000 0010
-125的补码:1111 1111 1111 1111 1111 1111 1000 0011
-125>>4: 1111 1111 1111 1111 1111 1111 1111 1000(补码)
-125>>4: 1111 1111 1111 1111 1111 1111 1111 0111(反码)
-125>>4: 1000 0000 0000 0000 0000 0000 0000 1000(原码)
*/
System.out.println(125 >>> 4);//正数的右移和无符号右移是一样的
System.out.println(-125 >>> 4);
/*
-125的原码:1000 0000 0000 0000 0000 0000 0111 1101
-125的反码:1111 1111 1111 1111 1111 1111 1000 0010
-125的补码:1111 1111 1111 1111 1111 1111 1000 0011
-125>>>4: 0000 1111 1111 1111 1111 1111 1111 1000(补码)
*/
System.out.println(125 & 4);
/*
125的补码:0000 0000 0000 0000 0000 0000 0111 1101
4的补码: 0000 0000 0000 0000 0000 0000 0000 0100
125 & 4: 0000 0000 0000 0000 0000 0000 0000 0100
*/
System.out.println(125 & 10);//8
/*
125的补码: 0000 0000 0000 0000 0000 0000 0111 1101
10的补码: 0000 0000 0000 0000 0000 0000 0000 1010
125 & 10: 0000 0000 0000 0000 0000 0000 0000 1000
*/
System.out.println(125 | 10);//127
/*
125的补码: 0000 0000 0000 0000 0000 0000 0111 1101
10的补码: 0000 0000 0000 0000 0000 0000 0000 1010
125 | 10: 0000 0000 0000 0000 0000 0000 0111 1111
*/
System.out.println(125 ^ 10);//119
/*
125的补码: 0000 0000 0000 0000 0000 0000 0111 1101
10的补码: 0000 0000 0000 0000 0000 0000 0000 1010
125 ^ 10: 0000 0000 0000 0000 0000 0000 0111 0111
*/
System.out.println(~10);//-11
/*
10的补码: 0000 0000 0000 0000 0000 0000 0000 1010
~10: 1111 1111 1111 1111 1111 1111 1111 0101(补码)
~10: 1111 1111 1111 1111 1111 1111 1111 0100(反码)
~10: 1000 0000 0000 0000 0000 0000 0000 1011(原码)
*/
System.out.println(1 << 33);
/*
1的补码:0000 0000 0000 0000 0000 0000 0000 0001
1<<33: 0000 0000 0000 0000 0000 0000 0000 0010
等价于1<<(33-32)
*/
System.out.println(4 >> 33);
/*
4的补码:0000 0000 0000 0000 0000 0000 0000 0100
4>>33: 0000 0000 0000 0000 0000 0000 0000 0010
等价于4>>(33-32)
*/
byte b = 1;
System.out.println(b << 2);//4
/*
byte按理1个字节
1的补码:0000 0001
b<<2: 0000 0000 0000 0000 0000 0000 0000 0100
*/
System.out.println(b << 9);//512
/*
byte按理1个字节,byte类型运算升级为int
1的补码:0000 0001
b<<9: 0000 0000 0000 0000 0000 0010 0000 0000
*/
}
}
运算符的优先级:
(1)赋值类运算符是最低,也就最后算
(2)大体的排序:算术–>位–>比较–>逻辑–>三元–>赋值
如果我们记不清具体的运算符的优先级,建议:
(1)不要写太复杂的式子
(2)你想要先算的加()
在程序中如何表示一个字符?
(1)可见字符:‘一个字符’
(2)不可见字符:
换行:\n
回车:\r
制表位:\t
退格:\b
斜杠:\
双引号:"
单引号:’