Java 基础笔记

58 阅读5分钟

基本语法

标识符和关键字

在我们编写程序的时候,需要大量地为程序、类、变量、方法等取名字,于是就有了 标识符 。简单来说, 标识符就是一个名字。而关键字是被赋予特殊含义的标识符

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<<10x>>42等同于x>>10x >>>42等同于x >>> 10

基本数据类型

Java中有8种基本数字类型,4整2浮1字1布:

byte, short, int, long

float, double

char

boolean

详细表格如下

基本类型bitbyte默认值取值范围
byte810-128 ~ 127
short1620-2^15 ~ 2^15 - 1
int3240-2^31 ~ 2^31 - 1
long6480l-2^63 ~ 2^63 - 1
char162'u0000'0 ~ 2^16 -1
float3240f( -2^128, -2^(-149) ) U ( 2^(-149), 2^149 )
double6480d

基本类型和包装类

存储:基本数据类型的局部变量存储在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

无限循环的小数无法用有限宽度的基本数据类型存储,因此会截断

解决精度问题有两种方式:

  1. 规定误差范围,误差范围内的结果都是可接受的
  2. 使用BigDecimal

变量

为什么成员变量有默认值,但是局部变量没有?

对于编译器来说,局部变量没有默认值可以直接报错,但是成员变量可以在运行时赋值,无法判断,若在用户编码时提示无默认值影响体验,因此自动赋值。

字符型常量与字符串常量

字符串常量是地址,字符型常量是整型值(ASCII)可以参与运算

方法

静态方法为何不能访问非静态成员?

静态方法是类的方法,非静态成员是对象的成员,可能该成员所属的对象还未实例化

重载与重写

重载是让一个方法接收不同参数,使该方法更灵活,本质是多个同名方法用参数来区分;重写是扩展方法的功能,由子类定义同名方法来实现,本质还是一个方法。

注:如果方法的返回值是引用类型,重写时是可以返回该引用类型的子类的。

代理

为什么要有代理?

  1. 保护委托对象
  2. 降低耦合度,拒绝大量继承和接口实现 cloud.tencent.com/developer/a…

JDK动态代理为何只能代理接口?

juejin.cn/post/726531…

  • 已知增强类的方法有:
  1. 继承类
  2. 实现接口
  3. 持有类的对象

CGLIB与JDK

  • 效率:创建对象JDK快;执行效率CGLIB高,CGLIB 需要创建更多.class文件
  • 实现方式:JDK通过生成实现委托对象接口的匿名类使用反射的 invoke 方法来执行指定方法;CGLIB使用字节码处理框架ASM,生成继承被代理类的子类,通过 FastClass 机制来执行指定方法

注:FastClass机制是根据委托类的方法名生成对应的索引,运行时只需委托对象和索引就可以指定调用某个方法