一. 数据类型
Java中一共有8中基本数据类型,此外还有很多引用数据,它们如下图所示:
1. 整数类型
注意:Java当中的整数没有所谓的无符号(unsigned)类型,统一都是有符号的。
1.1 整型(int)
下面定义一个整型变量:
int num = 10;
注意事项:
变量指的是程序运行时其值可以改变的量
类型则是对变量的种类进行了划分,不同的类型的变量具有不同的特性
变量名是变量的标识,后续都是通过这个名字来使用变量
int 表示变量的类型是一个整型
Java中 = 表示赋值(和数学不一样,数学中表示等价),意思是给变量设置一个初始值或重新给值。
初始化操作是可选的,但是建议创建变量的时候都显式初始化
不要忘记最后的分号,否则会编译失败
int类型的大小和表示范围
在Java中,一个int类型的变量占4个字节(即32个bit位)和操作系统没有直接关系,这充分说明了Java的可移植性强。4个字节表示的数据范围是[-2^31, +2^31-1]:
使用以下代码查看Java中的int数据范围:
// 输出:2147483647 System.out.println(Integer.MAX_VALUE); // 输出:2147483648 System.out.println(Integer.MIN_VALUE);
PS:Integer是int的包装类,相当于int的puls版本。
如果运算的结果超出了int的最大范围,就会出现溢出的情况:
1.2 长整型(long)
21亿这样的数字对于当前的大数据时代来说,是很容易超出的,针对这种情况,我们就需要使用更大范围的数据类型来表示。Java中提供了long类型。
下面定义三个长整型变量:
// long类型变量的值有以下三种写法 long num1 = 10; long num2 = 10L; long num3 = 10l;
注意事项:
初始化设定的值为10L表示这是一个长整型的字面常量,10l也可以。
使用10初始化也可以,10字面常量的类型是int,赋值时会发生整型提升。10L的类型是long,使用10L或者10l更好一些。
Java中没有long long类型。
long类型的大小和表示范围
Java中long类型占8个字节,表示的数据范围[-2^63, +2^63-1],使用以下代码查看Java中长整型的数据范围:
// 输出:9223372036854775807 System.out.println(Long.MAX_VALUE); // 输出:-9223372036854775808 System.out.println(Long.MIN_VALUE);
这个数据范围远超过int的表示范围,足够绝大部分的工程场景使用。
1.3 字节类型(byte)
只占一个字节的byte类型只能表示整数;注意和C/C++中的char区分开,char表示出来的是字符。
byte num = 1;
注意事项:
字节类型和字符类型互不相干。
字节类型表示的也是整数。只占一个字节, 表示范围较小[-128, +127]。
在Java当中,整数类型都是有取值范围的,存储数据的时候,不要超过那个范围,编译器会针对类型对变量的值进行检查是否在合法范围内。
1.4 短整型(short)
和C/C++一样,Java中也有short类型。
short num = 10;
注意事项:
short类型占用2个字节,表示的数据范围是[-32768,+32767]。
这个表示范围比较小,一般不推荐使用。
2. 浮点数类型
浮点数类型有两种:float、double,它们能表示的精度不一样,后者要大一些。
2.1 双精度浮点型(double)
double a = 1.0; double b = 2.0; System.out.println(a / b);// 0.5
Java中的double是8个字节,但实际上浮点数的内存布局和整数差别很大,我们看下面这段代码:
double num = 1.1; // 输出 1.2100000000000002 System.out.println(num * num);
Java中double类型的内存布局遵守IEEE 754标准(和C语言一样),尝试使用有限的内存空间表示可能的无限小数,这势必会存在一定的精度误差,所以不能单纯地用2^n形式表示来表示浮点数的数据范围。
2.2 单精度浮点型(float)
float类型在Java中占4个字节,同样遵守IEEE 754标准。由于表示的数据精度范围较小,一般在工程上用到浮点数都优先考虑double,不推荐使用 float。
float num = 1.1f;// 写作1.1F也可以,但不能不写
注意:float类型的变量在初始化给值时一定要加上f或F的标识。不然会报错:java: 不兼容的类型: 从double转换到float可能会有损失,因为在Java中浮点数字面常量值的类型默认是double(8字节)的,如果直接把它赋值给float(4字节)变量会有数据损失。
4. 字符类型(char)
char ch = 'A'; // 打印字符A的三种方法 System.out.println(ch);// 通过char类型变量来打印 System.out.println('A');// 通过字符的字面常量来打印 System.out.println((char)65);// 通过'A'的Unicode码来表示
注意事项:
Java中使用单引号 + 单个字母的形式表示字符的字面常量。
计算机中存储的字符本质上还是一个整数,在C语言中使用ASCII来表示字符,而Java中使用Unicode表示字符,因此在Java中一个字符占用两个字节,两个字节的话可以表示的字符种类更多,包括中文。
4. 字符串类型(String)
和上面的类型不同,String不是基本类型,而是引用类型。Java中使用双引号 + 若干字符的方式表示字符串常量值:
注意事项:
字符串中的一些特定的不太方便直接表示的字符需要进行转义:
字符串的 + 操作,表示字符串拼接:
当一个 + 表达式两边中存在至少一个字符串操作数的时候,执行的都是字符串拼接行为:
5. 布尔类型(boolean)
相当于C++中的bool类型,在Java中叫做boolean,不过二者还是有区别的。
boolean flag = true;
注意事项:
boolean类型的变量只有两种取值:true和false,不能再有其他取值。
Java中的boolean类型和int不能相互转换,不存在0表示false,非0表示true这样的说法。
在JVM的规范当中,并没有规定布尔类型的大小。有些书会说1bit,有些书又说是1byte,这个没有明确规定。
6. 几点补充
6.1 变量命名规则
硬性规则(必须遵守):
变量名必须由数字、字母(大小写都可)、下划线构成,不能包含其他特殊符号。
数字不能开头:
变量名不能和Java的“关键字”重复。
Java中的变量名是大小写敏感的,例如num和Num是两个不同的变量。
软性规则(建议遵守):
变量名的词性推荐使用名词。
变量命名要具有描述性,能够见名知义。
当我们使用一个单词描述不清楚的时候,可以使用多个单词来命名。这时变量命名推荐小驼峰命名法,即除了第一个单词之外,后面单词的首字母都大写,如下图所示:
6.2 区分常量和变量
6.3 理解类型转换
Java作为一个强类型编程语言,当不同类型之间的变量相互赋值的时候, 会进行较严格的校验,先看以下几个代码场景:
场景一:int 和 long/double 相互赋值
int a = 10; long b = 20; a = b; // 编译出错,提示可能会损失精度 b = a; // 编译通过 int a = 10; double b = 1.0; a = b; // 编译出错, 提示可能会损失精度. b = a; // 编译通过.
分析:
long表示的范围更大,可以将int赋值给long,但是不能将long赋值给int。
double表示的范围更大,可以将int赋值给double,但是不能将double赋值给 int。
结论:不同数字类型的变量之间赋值:精度可以扩大但不能缩小,即使类型改变了也要尽可能的地保护数据安全。
场景二:int 和 boolean 相互赋值
int a = 10; boolean b = true; b = a; // 编译出错, 提示不兼容的类型 a = b; // 编译出错, 提示不兼容的类型
结论:int和boolean是毫不相干的两种类型,二者不能相互赋值。
场景三:整型字面值常量给 byte 赋值
/ PS: 1、byte表示的数据范围是[-128, +127] // 2、256已经超过了byte的范围, 而100还在范围之内 byte a = 100; // 编译通过 byte b = 256; // 编译报错, 提示:从int转换到byte可能会有损失
结论:使用字面值常量赋值的时候,Java会自动进行一些检查校验,判定赋值是否合理:
整数的话,会检查字面常量值是否在变量类型所能表示范围之内。
浮点数的话,会检查是否会有精度丢失,注意浮点数字面常量值类型默认是double,如果要赋值给float的话需要在数字最后加上F或f表示这个浮点数字面常量是float类型的。
创建四:使用强制类型转换
int a = 0; double b = 10.5; a = (int)b;// 编译通过 int a = 10; boolean b = false; b = (boolean)a; // 编译出错, 提示不兼容的类型
结论:
强制类型转换可能会导致精度丢失,如上面的例子中,赋值之后,10.5 就变成10了,小数点后面的部分被丢弃。
强制类型转换不是一定能成功,互不相干的类型之间就无法强转。
类型转换小结
不同数字类型的变量之间赋值,表示范围更小的类型能自动隐式类型转换成范围较大的类型。
不同数字类型的变量之间赋值,如果需要把范围大的类型赋值给范围小的,需要强制类型转换,但是可能会发生精度丢失。
将一个字面值常量进行赋值的时候,Java会自动针对这个数字和变量的类型所能表示的范围进行检查:
整数的话,会检查字面常量值是否在变量类型所能表示范围之内。
浮点数的话,会检查是否会有精度丢失,注意浮点数字面常量值类型默认是double,如果要赋值给float的话需要在数字最后加上F或f表示这个浮点数字面常量是float类型的。
6.4. 理解类型提升
不同数字类型的变量在运算时会发生数值提升,具体看下面两个场景:
场景一:int 和 long 混合运算
int a = 10; long b = 20; int c = a + b; // 编译出错,提示将long转成int会丢失精度 long d = a + b;// 编译通过
分析:
当int和long混合运算的时候,int会提升成long,得到的结果仍然是long类型,需要使用long类型的变量来接收结果。
如果非要用int来接收结果,就需要进行强制类型转换。
场景二:byte 和 byte 的运算
分析:
由于计算机的CPU通常是按照4个字节为单位从内存中读写数据,为了硬件上实现方便,诸如byte和short这种低于4个字节的数字类型,会先提升成int,再参与计算。
byte和byte都是相同类型,但是出现编译报错,原因是:虽然a和b都是 byte,但是计算a+b时会先将a、b都提升int,再进行计算,最终得到的结果也是int,这是赋给c,就会出现上述错误。
而右边10和20都是普通的整型字面常量,最终结果30也是一个普通字面常量,所以不会报错。
类型提升小结
不同数字类型的变量混合运算,范围小的会提升成范围大的,最后得到的结果是一个类型范围最大的临时变量。
对于short、byte这种小于4个字节数字类型,会先提升成4个字节的int再做运算。
6.5 int和String之间的相互转换
int转成String:利用String包装类的valueOf()方法,即可返回一个String类型的由整数转化而来的字符串,注意 valueOf 中的O是大写的。
int num = 10; String s = String.valueOf(num);
String转成int:利用Integer包装类的parseInt()方法,把需要转化的字符串作为参数传入即可,注意 parseInt 中的I是大写的。
String s = "10"; int num = Integer.parseInt(s);
小结:对标C++中的转换
二. 运算符
PS:运算符之间是有优先级的,我们不需要去记忆谁的优先级高或低,只需根据自己的逻辑加上括号即可。
1. 算术运算符
算术运算符包括如下三个大类:
注意事项:
%表示取余,不仅仅可以对int求模,也能对double来求模
取模就是取余数,最终结果的正负号取决于余数
0不能作为除数和取模数
自增/自减运算符,都有各自的前置和后置形式。自增使用时注意以下两点:
如果不取自增运算的表达式的返回值,则前置自增和后置自增没有区别
如果取表达式的返回值,则前置自增的返回值是自增之后的值,后置自增的返回值是自增之前的值。
2. 关系运算符
关系运算符主要有六个:> < >= <= == !=,注意关系运算符的表达式返回值都是boolean类型。
int a = 10; int b = 20; System.out.println(a == b);// false System.out.println(a != b);// true System.out.println(a < b); // true System.out.println(a > b); // false System.out.println(a <= b);// true System.out.println(a >= b);// false
3. 逻辑运算符
逻辑运算符主要有三个:&& || !,注意逻辑运算符的操作数(操作数往往是关系运算符的结果)和返回值都是boolean。
逻辑与 &&:全true才true,都则为false,这是个双目运算符
// 对于&&,如果左侧表达式值为false, // 则表达式的整体的值一定是false,无需计算右侧表达式 System.out.println((10 > 20) && (10/0 == 0));// 打印 false
逻辑或 ||:全flase才false,否则为true,这是个双目运算符
// 对于||,如果左侧表达式值为true // 则表达式的整体的值一定是true, 无需计算右侧表达式 System.out.println((10 < 20) || (10 / 0 == 0));// 打印 true
逻辑非 !:操作数为true,结果为false;操作数为false,结果为true(这是个单目运算符,只有一个操作数)
int a = 10; int b = 20; System.out.println(!(a < b));// fasle
4. 位运算符
位运算符主要有四个:& | ~ ^。Java中对数据操作的最小单位不是字节, 而是二进制位,而位操作表示的就是按二进制位运算。
计算机内部都是使用二进制来存储和表示数据的(即01构成的序列), 位运算就是在按照二进制位的每一位依次进行计算。
按位与 &:这是个双目运算符。两个二进制位中有0则结果为0,都是1结果才为1。
按位或 |:这是个双目运算符。两个二进制位中有1则为1,都是0结果才为0。
按位取反 ~:这是个单目运算符,运算规则如下:
如果该二进制位为0,则转为1
如果该二进制位为1,则转为0
5. 移位运算符
移位运算符有三个:<< >> >>>,它们都是按照二进制位来运算的。
左移 <<:最左侧位不要了,最右侧补0
右移 >>:最右侧位不要了,最左侧补符号位(正数补0,负数补1)
无符号右移 >>>:最右侧位不要了,最左侧不论正负数,统一都补0
移位运算符小结
左移 1 位,相当于原数字 * 2。左移 N 位,相当于原数字 * 2的N次方
右移 1 位,相当于原数字 / 2。右移 N 位,相当于原数字 / 2的N次方
在计算机中计算移位的效率高于计算乘除,当某个代码正好乘除2的N次方的时候,我们可以用移位运算代替,这样效率会高点。
移动负数位或者移位位数过大都没有意义
6. 条件运算符
条件运算符只有一个,也是Java中唯一的一个三目运算符。其格式如下:
表达式1 ? 表达式2 : 表达式3
当表达式1的值为true时,整个表达式的结果为表达式2的值(表达式3不会被执行)
当表达式1的值为false时,整个表达式的值为表达式3的值(表达式2不会被执行)
三. 注释
注释是为了让代码更容易被读懂而附加的描述信息。不参与编译运行,但是却非常重要。
时刻牢记!代码写出来是为了给人看的,更是为了给三个月后的你自己看的。
1. 基本规则
Java中的注释主要分为以下三种:
单行注释:// 注释内容(用的最多)
多行注释:/* 注释内容 */(不推荐)
文档注释: /** 文档注释 */(常见于方法和类之上描述方法和类的作用),可用来自动生成文档。
2. 注释规范
内容准确:注释内容要和代码一致、匹配,并在代码修改时及时更新
篇幅合理:注释既不应该太精简,也不应该长篇大论
使用中文:一般中国公司都要求使用中文写注释,外企另当别论
积极向上:注释中不要包含负能量(例如:领导SB等)