基本语法
标识符和关键字
在我们编写程序的时候,需要大量地为程序、类、变量、方法等取名字,于是就有了 标识符 。简单来说, 标识符就是一个名字。而关键字是被赋予特殊含义的标识符。
Java关键字大全
- 访问控制:public, protected, private
- 类,方法和变量修饰符:abstract, class, static, final, new, extends, implement, interface, native, strictfp, sychronized, transient, volatile, enum
- 程序控制:break, continue, return, do, while, if, else, for, instanceof, switch, case, default, assert
- 错误处理:try, catch, throw, throws, finally
- 包相关:import, package
- 基本类型:boolean, byte, char, double, float, int, long, short
- 变量引用:super, this, void
- 保留字:goto, const
移位运算符
-
<<:左移运算符,向左移若干位,高位丢弃,低位补零。x << 1,相当于 x 乘以 2(不溢出的情况下)。 -
>>:带符号右移,向右移若干位,高位补符号位,低位丢弃。正数高位补 0,负数高位补 1。x >> 1,相当于 x 除以 2。 -
>>>:无符号右移,忽略符号位,空位都以 0 补齐
如果移位运算的位数超出数据最大位数,则会先求余再运算:
x<<42等同于x<<10,x>>42等同于x>>10,x >>>42等同于x >>> 10
基本数据类型
Java中有8种基本数字类型,4整2浮1字1布:
byte, short, int, long
float, double
char
boolean
详细表格如下
| 基本类型 | bit | byte | 默认值 | 取值范围 |
|---|---|---|---|---|
| byte | 8 | 1 | 0 | -128 ~ 127 |
| short | 16 | 2 | 0 | -2^15 ~ 2^15 - 1 |
| int | 32 | 4 | 0 | -2^31 ~ 2^31 - 1 |
| long | 64 | 8 | 0l | -2^63 ~ 2^63 - 1 |
| char | 16 | 2 | 'u0000' | 0 ~ 2^16 -1 |
| float | 32 | 4 | 0f | ( -2^128, -2^(-149) ) U ( 2^(-149), 2^149 ) |
| double | 64 | 8 | 0d |
基本类型和包装类
存储:基本数据类型的局部变量存储在JVM栈中的局部变量表中,基本数据类型的成员变量和包装对象都存在JVM的堆中
默认值:基本数据类型有自己的默认值,包装类默认是null
比较:基本数据类型用==,包装类用equals()方法(包装类的==是地址比较,同一个地址就是true)
包装类的缓存机制
由于包装类是对象,占用空间较大,因此缓存一定范围内基本数据类型的包装对象。
Java包装类缓存是通过静态成员数组cache实现的:
- Integer 类:默认缓存了-128 到 127 之间的整数。
- Long 类:默认缓存了-128 到 127 之间的长整数。
- Short 类:默认缓存了-128 到 127 之间的短整数。
- Byte 类:默认缓存了-128 到 127 之间的字节。
- Character 类:默认缓存了 0 到 127 之间的字符。
当使用valueOf方法初始化包装对象时,若值在范围内会返回缓存数组中的对象,不再新建对象。而用new来初始化则会新建对象。
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);
结果是false
因此所有包装类之间值的比较都使用equals()方法
拆箱与装箱
Integer i = 10; //装箱
int n = i; //拆箱
Integer i = 10等价于Integer i = Integer.valueOf(10)
int n = i等价于 int n = i.intValue()
频繁装箱拆箱会影响性能,尽量避免不必要的装箱拆箱
private static long sum() {
// 应该使用 long 而不是 Long
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}
浮点数精度丢失
float a = 2.0f - 1.9f;
float b = 1.8f - 1.7f;
System.out.println(a);// 0.100000024
System.out.println(b);// 0.099999905
System.out.println(a == b);// false
无限循环的小数无法用有限宽度的基本数据类型存储,因此会截断
解决精度问题有两种方式:
- 规定误差范围,误差范围内的结果都是可接受的
- 使用
BigDecimal
变量
为什么成员变量有默认值,但是局部变量没有?
对于编译器来说,局部变量没有默认值可以直接报错,但是成员变量可以在运行时赋值,无法判断,若在用户编码时提示无默认值影响体验,因此自动赋值。
字符型常量与字符串常量
字符串常量是地址,字符型常量是整型值(ASCII)可以参与运算
方法
静态方法为何不能访问非静态成员?
静态方法是类的方法,非静态成员是对象的成员,可能该成员所属的对象还未实例化
重载与重写
重载是让一个方法接收不同参数,使该方法更灵活,本质是多个同名方法用参数来区分;重写是扩展方法的功能,由子类定义同名方法来实现,本质还是一个方法。
注:如果方法的返回值是引用类型,重写时是可以返回该引用类型的子类的。
代理
为什么要有代理?
- 保护委托对象
- 降低耦合度,拒绝大量继承和接口实现 cloud.tencent.com/developer/a…
JDK动态代理为何只能代理接口?
- 已知增强类的方法有:
- 继承类
- 实现接口
- 持有类的对象
CGLIB与JDK
- 效率:创建对象JDK快;执行效率CGLIB高,CGLIB 需要创建更多.class文件
- 实现方式:JDK通过生成实现委托对象接口的匿名类使用反射的 invoke 方法来执行指定方法;CGLIB使用字节码处理框架ASM,生成继承被代理类的子类,通过 FastClass 机制来执行指定方法
注:FastClass机制是根据委托类的方法名生成对应的索引,运行时只需委托对象和索引就可以指定调用某个方法