1. 变量和类型
变量指的是程序运行时可变的量,相当于开辟一块空间来保存一些数据。
类型则是对变量的种类进行了划分,不同类型的变量具有不同的特性。
1.1 整型变量(重点)
基本语法格式:
int 变量名 = 初始值;
代码示例:
int num = 10; //定义一个整型变量
System.out.println(num);
注意事项:
- int 表示变量的类型是一个整型
- Java中‘=’表示赋值,意思是给变量设置一个初始值。
- 初始化操作是可选的,但是建议创建变量的时候都先初始化。
- 每个语句写完后不要忘记封号,否则会编译失败。
- ‘//’表示注释,注释作为代码的解释说明部分,不参与编译运行。
在Java中,一个int变量占4个字节,和操作系统没有直接关系。
什么是字节? - 字节是计算机表示空间大小的基本单位。
- 计算机使用二进制表示数据,我们认为8个二进制位(bit)为一个字节(Byte)。
- 我们平时的计算机为8GB内存,意思是8G个字节。
- 其中1KB = 1024Byte, 1MB = 1024KB, 1GB = 1024MB.
- 所以8GB相当于80多亿个字节。
4个字节表示的数据范围是-231 -> 231-1 ,也就是-21亿到+21亿。
使用以下代码可以查看Java中的整型数据范围:
System.out.println(Integer.MAX_VALUE);//int 的最大值
System.out.println(Integer.MIN_VALUE);//int 的最小值
如果运算的结果超出了int的最大范围,就会出现溢出的情况
int maxValue = Integer.MAX_VALUE;
System.out.println(maxValue+1);int minValue = Integer.MIN_VALUE;
System.out.println(minValue-1);
21亿这样的数字对于当前的大数据时代来说,是很容易超出的,针对这种情况,我们就需要使用更大范围的数据类型来表示。Java中提供了long类型。
1.2 长整型变量
基本语法格式:
long 变量名 = 初始值;
代码示例:
long num = 10L;//定义一个长整型变量,初始值写作10L(建议后面的L大写,防止和数字1混淆)
System.out.println(num);
注意事项:
- 基本语法格式和创建int 变量基本一致,只要把类型修改成long。
- 初始化设定的值为10L,表示一个长整型的数字。
Java中long类型占8个字节,表示的数据范围-263 ->263-1
使用以下代码查看Java中的长整型数据范围:
System.out.println(Long.MAX_VALUE);
System.out.println(Long.MIN_VALUE);
这个数据范围远超过int的表示范围,足够绝大部分的工程场景使用。
1.3 双精度浮点型变量(重点)
基本语法格式:
double 变量名 = 初始值;
代码示例:
double n = 1.0;
System.out.println(n);
神奇的代码1:
int a = 1;
int b = 2;
System.out.println(a / b);
//执行结果:0
在Java中,int 除以 int 的值仍然是int(会直接舍弃小数部分)。
如果想得到0.5,需要使用double类型计算。
double a = 1;
double b = 2;
System.out.println(a / b);
//执行结果:0.5
神奇的代码2:
double a = 1.1;
System.out.println(num * num);
//执行结果:1.2100000000000002
Java中的double虽然也是8个字节,但是浮点数的内存布局和整数差别很大,不能单纯的用2n 的形式表示数据范围。
Java的double类型的内存布局遵守IEEE 754标准(和C语言一样),尝试使用有限的内存空间表示可能无限的小数,势必会存在一定的精度误差。
1.4 单精度浮点型变量
基本格式:
float 变量名 = 初始值;
代码示例:
float num = 1.0f; //写作 1.0F 也可以
System.out.println(num);
float类型在Java中占4个字节,同样遵守IEEE 754标准,由于表示的数据精度范围较小,一般在工程上用到浮点数都优先考虑double,不太推荐使用float。
1.5字符类型变量
基本格式:
char 变量名 = 初始值;
代码示例:
char ch = 'A';
注意事项:
- Java中使用单引号+单个字符表示字面值。
- 计算机中的字符本质上是一个整数,在C语言中使用ASCII表示字符,而Java中使用Unicode表示字符,因此一个字符占用两个字节,表示的字符种类更多,包括中文。
使用一个字符表示一个汉字:
char ch = '狸';
System.out.println(ch);
执行Javac的时候可能出现以下错误:
Test.java:3:错误:未结束的字符文字char ch = '鍛?';
此时我们在执行javac时加上-encoding UTF-8选项即可
java -encoding UTF-8 Test.java
1.6 字节类型变量
基本语法格式:
byte 变量名 = 初始值;
代码示例:
byte value = 0;
System.out.println(value);
注意事项:
- 字节类型表示的也是整数,只占一个字节,表示范围较小(-128 -> +127)。
- 字节类型和字符类型互不相干。
1.7 短整型变量
基本语法格式:
short 变量名 = 初始值;
代码示例:
short value = 0;
System.out.println(value);
注意事项:
- short占用2个字节,表示的数据范围是-32768 -> +32767。
- 这个表示范围较小,一本不推荐使用。
1.8 布尔类型变量
基本语法格式:
boolean 变量名 = 初始值;
代码示例:
boolean value = true;
System.out.println(value);
注意事项:
- boolean类型的变量只有两种取值,true表示真,false表示假。
- Java的boolean类型的变量和int 不能互相转换,不存在1表示true,0表示false这样的用法。
- boolean类型有些JVM的实现是占1个字节,有些是占1个比特位,这个没有明确规定。
boolean value = true;
System.out.println(value + 1);
/*编译会出现如下错误
java: 二元运算符 '+' 的操作数类型错误//第一个类型: boolean第二个类型: int/*
1.9 字符串类型变量
把一些字符放到一起就构成了字符串。
基本语法格式:
String 变量名 = "初始值”;
代码示例:
String name = "ali";
System.out.println(name);
注意事项:
- Java使用双引号+若干字符的方式表示字符串字面值。
- 和上面的类型不同,String不是基本类型,而是引用类型。
- 字符串中的一些特定的不太方便直接表示的字符需要进行转义。
转义字符示例:
//创建一个字符串 My name is "阿狸"
String name = "my name is \"阿狸\"";
转义字符有很多,其中几个比较常见的如下:
字符串‘+’操作,表示字符串拼接:
System.out.println(num);
String a = "hello";
String b = "world";
String c = a + b;
System.out.println(c);
//执行结果:helloworld(这里没有空格,可以自己加)
还可以用字符串和整数进行拼接:
float num = 1.0f;
String str = "result =";
int a = 10;
int b = 20;
String result = str + a + b;
System.out.println(result);
//执行结果:result = 1020
以上代码说明,当一个‘+’表达式中存在字符串的时候,都是执行字符串的拼接行为。
因此我们可以很方便的使用System.out.println同时打印多个字符串或数字。
1.10 变量的作用域
也就是该变量能生效的范围,一般是变量定义所在的代码块(大括号)。
public static void main(String[] args) {int x = 10;System.out.println(x); //编译通过}System.out.println(x); //编译失败,找不到x
1.11 变量的命名规则
硬性指标:
1.一个变量名只能包含数字、字母、下划线。
2.数字不能开头。
3.变量名是大小写敏感的,即num和Num是两个不同的变量。
注意:虽然语法上也允许使用中文/美元符($)命名变量,但是强烈建议不推荐这样做。
软性指标:
1.变量命名要具有描述性,见名知意。
2.变量名不宜使用拼音(但是不绝对)。
3.变量名的词性推荐使用名词。
4.变量命名推荐小驼峰命名法,当一个变量名由多个单词构成的时候,除了第一个单词之外,其他单词首字母都大写。
小驼峰命名示例:
int maxValue = 100;
String studentName = "阿狸";
1.12 常量
上面讨论的都是各种规则的变量,每种类型的变量也对应着一种相同类型的常量。
常量在运行时类型不能发生改变。
常量主要有以下两种体现形式:
- 字面值常量
10 | int 字面值常量(十进制) |
010 | int 字面值常量(八进制)由数字0开头,010即十进制的8 |
0x10 | int 字面值常量(十六进制)由数字0x开头,0x10即十进制的16 |
10L | long字面值常量,也可以写作10l(小写的L) |
1.0 | double 字面值常量,也可以写作1.0d,或者1.0D |
1.5e2 | double 字面值常量,科学计数法表示,相当于1.5 * 102 |
1.0f | float 字面值常量,也可以写作1.0F |
true | boolean 字面值常量,同样的还有false |
’ a ’ | char 字面值常量,单引号中只能有一个字符 |
" abc " | String 字面值常量,双引号中可以有多个字符 |
- final 关键字修饰的常量
final int a = 10;
a = 20;//编译出错,无法为最终变量a分配值
常量不能在程序运行过程中发生修改。
1.12 理解类型转换
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;//编译通过
1.long 表示的范围更大,可以将 int 赋值给 long ,但是不能将 long 赋值给 int。
2.double 表示的范围更大,可以将 int 赋值给 double,但是不能将 double 赋值给 int 。
结论:
不同数字类型的变量之间赋值,表示范围更小的类型能隐式转换成范围较大的类型,反之则不行。
int 和 boolean 相互赋值
int a = 10;
boolean b = true;
b = a;//编译出错,提示不兼容的类型
a = b;//编译出错,提示不兼容的类型
结论:
int 和 boolean 是毫不相干的两种类型,不能相互赋值。
int 字面值常量给 byte 赋值
byte a = 100;//编译通过
byte b = 256;//编译报错,从int 转换到byte 可能会有损失
注意:byte 表示的数据范围是-128 -> +127,256已经超过范围,而100还在范围之内。
结论:
使用字面值常量赋值的时候,Java会自动进行一些检查校验,判定赋值是否合理。
使用强制类型转换
int a = 0;
double b = 10.5;
a = (int)b;int a = 10;
boolean b = false;
b = (boolean)a;//编译出错,提示不能兼容的类型
结论:
使用(类型)的方式可以将double 类型强转成 int 。但是
1.强制类型转换可能会导致精度丢失。如刚才的例子中,赋值之后,10.5就变成10了,小数点后面的部分被忽略。
2.强制类型转换不一定能成功,互不相干的类型之间无法强转。
类型转换小结:
- 不同数字类型的变量之间赋值,表示范围更小的类型能隐式转换成范围较大的类型。
- 如果需要把范围大的类型赋值给范围小的,需要强制类型转换,但是可能会精度丢失。
- 将一个字面值常量进行赋值的时候,Java会自动针对数字范围进行检查。
1.13 理解数值提升
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 的运算
byte a = 10;
byte b = 20;
byte c = a + b;
System.out.println(c);
//编译报错 从int 转换到 byte 可能会有损失
结论:
1.byte 和byte 都是相同类型,但是出现编译报错,原因是,虽然 a 和 b 都是byte,但是计算 a + b 会先将 a 和 b 都提升成 int ,再进行计算,得到的结果也是 int ,将结果赋给 c ,就会出现上述错误。
2.由于计算机的CPU通常是按照4个字节为单位从内存中读写数据,为了硬件上实现方便,诸如byte和short这种低于4个字节的类型,会先提升成 int ,再参与计算。
正确的写法:
byte a = 10;
byte b = 20;
byte c = (byte)(a + b);
System.out.println(c);
类型提升小结:
- 不同类型的数据混合运算,范围小的会提升成范围大的。
- 对于short,byte这种比4个字节小的类型,会先提升成4个字节的 int ,再运算。
1.14 int 和 String 之间的相互转换
int 转成 String
int num = 10;
//方法一:
String str1 = num + "";
//方法二:
String str2 = String.valueOf(num);
String 转成 int
String str = "100";
int num = Integer.parseInt(str);
1.15 小结:
- Java类型汇总,前面的内容重点介绍的是基本数据类型。
- 每种数据类型及其范围,是需要我们掌握的重点。
- 隐式类型转换和类型提升,是本节的难点,但是一般我们更推荐在代码中避免不同类型混用的情况,来规避类型转换和类型提升的问题。
2. 运算符
基本四则运算符 + - * /
规则比较简单,值得注意的是除法:
- int / int 结果还是 int ,需要使用double来计算
int a = 1;
int b = 2;
System.out.println(a / b);
//结果为0
- 0不能作为除数
- %表示取余,不仅可以对 int 求模,也能对double 来求模
System.out.println(11.5 % 2.0);
//运行结果 1.5
增量赋值运算符+= -= *= /= %=
int a = 10;
a += 1;//等价于a = a + 1
System.out.println(a);
自增 / 自减运算符++ - -
int a = 10;
int b = ++a;
System.out.println(b);
int c = a++;
System.out.println(c);
结论:
1.如果不取自增运算的表达式的返回值,则前置自增和后置自增没有区别。
2.如果取表达式的返回值,则前置自增的返回值是自增之后的值,后置自增的返回值是自增之前的值。
2.2 关系运算符
关系运算符主要有六个:==(等于) !=(不等于) < > <=(小于等于) >=(大于等于)
int a = 10;
int b = 20;
System.out.println(a == b);
System.out.println(a != b);
System.out.println(a > b);
System.out.println(a < b);
System.out.println(a >= b);
System.out.println(a <= b);
注意:
关系运算符的表达式返回值都是boolean 类型。
2.3 逻辑运算符(重点)
逻辑运算符主要有三个:&& || !
注意:
逻辑运算符的操作数(操作数往往是关系运算符的结果)和返回值都是boolean。
逻辑与
规则:两个操作数都为true,结果为true,否则结果为false。
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b && b < c);
逻辑或
规则:两个操作数都为false,结果为false,否则结果为true。
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b || b < c);
逻辑非
规则:操作数为true,结果为false;操作数为false,结果为true。(这是个单目运算符,只有一个操作数)。
int a = 10;
int b = 20;
System.out.println(!a < b);
短路求值
&&和 || 遵守短路求值的规则。
System.out.println(10 > 20 && 10 / 0 == 0);//打印false
System.out.println(10 > 20 || 10 / 0 == 0);//打印true
我们都知道,计算10 / 0会导致程序抛出异常,但是上面的代码却能正常运行,说明10 / 0并没有真正被求值。
结论:
1.对于&&,如果左侧表达式置为false,则表达式的整体一定是false,无需计算右侧表达式。
2.对于||,如果左侧表达式置为true,则表达式的整体一定是true,无需计算右侧表达式。
& 和 |(不推荐使用)
& 和 | 如果操作数为boolean的时候,也表示逻辑运算,但是和&& 以及 || 相比,它们不支持短路求值。
System.out.println(10 > 20 && 10 / 0 == 0);//程序抛出异常
System.out.println(10 > 20 || 10 / 0 == 0);//程序抛出异常
2.4 位运算符
Java 中对数据操作的最小单位不是字节,而是二进制位。
位运算符主要有4个 & | ~ ^
位操作表示按二进制位运算,计算机中都是使用二级制来表示数据的(0和1构成的序列),按位运算就是在按照二进制位的每一位依次进行计算。
按位与 &: 如果两个二进制位都是 1, 则结果为 1, 否则结果为 0。
举个栗子:
int a = 10;
int b = 20;
System.out.println(a & b);
进行按位运算, 需要先把 10 和 20 转成二进制, 分别为 1010 和 10100。(我自己记的是:两1为1,有0为0)
按位或 | : 如果两个二进制位都是 0, 则结果为 0, 否则结果为 1。
int a = 10;
int b = 20;
System.out.println(a | b);
运算方式和按位与相似。(我自己记的是:两0为0,有1为1)。
注意:
当 & 和 | 的操作数为整数(int, short, long, byte) 的时候, 表示按位运算, 当操作数为 boolean 的时候, 表示逻辑运算。
按位取反 ~ : 如果该位为 0 则转为 1, 如果该位为 1 则转为 0.
int a = 0xf;
System.out.printf("%x\n",~a);
注意:
- 0x 前缀数字为十六进制数字,十六进制可以看成是二进制的简化表达式,一个十六进制数字对应4个二进制位。
- 0xf 表示10进制的15,也就是二进制的1111.
- printf 能够格式化输出内容,%x表示按照十六进制输出。
- \n 表示换行符。
2.5 移位运算符(了解)
移位运算符有三个: << >> >>>
都是按照二进制位来运算
**左移 <<: **最左侧位不要了, 最右侧补 0.
int a = 0x10;
System.out.printf("%x\n",a << 1);
**右移 >>: **最右侧位不要了, 最左侧补符号位(正数补0, 负数补1)
无符号右移 >>>: 最右侧位不要了, 最左侧补 0
注意:
- 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方.
- 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方.
- 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替.
- 移动负数位或者移位位数过大都没有意义.
2.6 条件运算符
条件运算符只有一个: 表达式1 ? 表达式2 : 表达式3
当表达式1 的值为 true 时, 整个表达式的值为表达式2的值; 当表达式1的值为 false 时, 整个表达式的值为表达式3的值.
也就是:当表达式1的值为真时,执行表达式2,为假时执行表达式3.
也是 Java 中唯一的一个 三目运算符, 是条件判断语句的简化写法.
//求两个整数的最大值
int a = 10;
int b = 20;
int max = a > b ? a : b;
2.7 运算符的优先级
先看一段代码:
System.out.println(1 + 2 * 3);
结果为7,说明先计算了2*3,再计算+1
运算符之间是有优先级的,具体的规则我们不用刻意去记,在可能存在歧义的代码中加上括号即可。
2.8 小结:
- % 操作再 Java 中也能针对 double 来计算.
- 需要区分清楚 前置自增 和 后置自增之间的区别.
- 由于 Java 是强类型语言, 因此对于类型检查较严格, 因此像 && 之类的运算操作数必须是 boolean.
- 要区分清楚 & 和 | 什么时候是表示按位运算, 什么时候表示逻辑运算
整体来看,Java的运算符的基本规则和C语言基本一致。
3. 注释
Java中的注释主要分为以下三种:
单行注释:// 注释内容(用的最多)
多行注释:/* 注释内容*/(不推荐)
文档注释: /** 文档注释 */(常见于方法和类之上描述方法和类的作用),可用来自动生成文档
3.2 注释规范
- 内容准确: 注释内容要和代码一致, 匹配, 并在代码修改时及时更新.
- 篇幅合理: 注释既不应该太精简, 也不应该长篇大论.
- 使用中文: 一般中国公司都要求使用中文写注释, 外企另当别论.
- 积极向上: 注释中不要包含负能量(例如 领导 SB 等).
4. 关键字
关键字是Java中一些具有特定含义的单词
用于定义访问权限修饰符的关键字 | private protected public |
用于定义类,函数,变量修饰符的关键字 | abstract final static synchronized |
用于定义类与类之间关系的关键字 | extends implements |
用于定义建立实例及引用实例,判断实例的关键字 | new this super instanceof |
用于异常处理的关键字 | try catch finally throw throws |
用于包的关键字 | package import |
用于修饰符关键字 | native strictfp transient volatile assert |
定义的变量名不能和关键字冲突