以下内容参考Java 面试
Java 基础知识
Java 版本
- Java SE:适合开发桌面应用程序或简单的服务器应用程序。
- Java EE:适合开发复杂的企业级应用程序或 Web 应用程序。
JVM、JDK、JRE
- JVM (Java Virtual Machine):Java 虚拟机,能在不同系统中运行相同字节码并获得相同结果。只要满足 JVM 规范,任何人都可以开发自己的 JVM。
- JDK (Java Development Kit):Java 开发工具包,包含 JVM、核心类库、开发工具(如
javac
,javadoc
,jdb
,jconsole
,javap
)。 - JRE (Java Runtime Environment):Java 运行环境,包含 JVM 和核心类库,用于执行 Java 应用程序。
JDK 9 的模块系统
- 模块系统:JDK 9 引入了 94 个模块。
- jlink:新命令行工具,用于生成只包含所依赖的 JDK 模块的自定义运行时镜像,减少部署大小、内存占用,增加安全性和可维护性。
字节码
- 字节码 (.class 文件):JVM 可以理解的代码。
- 解释与编译:JVM 使用解释器逐行解释执行字节码;JIT 编译器会在运行时编译热点代码,提高执行效率。
AOT 编译 (Ahead-of-Time)
- 静态编译:程序在执行前被编译为机器码,启动速度更快,减少内存占用,提高安全性。
位运算符
<<
左移运算符:高位丢弃,低位补 0。x << n
相当于x * 2^n
。>>
右移运算符:带符号右移,高位补符号位。x >> n
相当于x / 2^n
。>>>
无符号右移:忽略符号位,空位补 0。
特别说明
位运算支持 int
和 long
,short
、byte
、char
在移位时会先转换为 int
。移动位数超过类型长度时,比如 x << 42
实际等同于 x << 10
。
public class Operation {
public static void main(String[] args) {
int i = 2;
System.out.println(i); // 输出:2
System.out.println(Integer.toBinaryString(i)); // 输出:10
}
}
基本数据类型与包装类
整数类型
byte
:1 字节,范围为 -128 到 127short
:2 字节,范围为 -32,768 到 32,767int
:4 字节,范围为 -2^31 到 2^31 - 1long
:8 字节,范围为 -2^63 到 2^63 - 1(数值后需加L
)
浮点类型
float
:4 字节,单精度浮点型,数值后需加f
或F
double
:8 字节,双精度浮点型
字符类型
char
:2 字节,用于表示单个字符
布尔类型
boolean
:1 位,取值为true
或false
注意事项
long
类型的值需要在数值后加上L
,否则会被当作int
处理。float
类型的数值后必须加f
或F
,否则默认是double
类型。
包装类
- 对应的包装类:
Byte
、Short
、Integer
、Long
、Float
、Double
、Character
、Boolean
- 包装类通常用于方法参数、对象属性以及泛型中。
基本类型 vs 包装类型
- 存储方式:基本类型的局部变量存储在栈中,成员变量(非
static
)存储在堆中;包装类型作为对象,通常存储在堆或元空间。 - 默认值:基本类型有默认值,包装类型没有默认值。
自动装箱与拆箱
- 装箱:将基本类型转换为其对应的包装类对象。
- 拆箱:将包装类对象转换为基本类型。
Integer i = 10; // 自动装箱
int n = i; // 自动拆箱
包装类型的缓存机制
- 缓存区间:
Byte
、Short
、Integer
、Long
的值在[-128, 127]
之间会被缓存。Character
缓存0
到127
之间的值。Boolean
缓存True
和False
。
BigDecimal 运算
创建 BigDecimal 对象
- 可以通过
BigDecimal(String val)
或BigDecimal.valueOf(double val)
创建BigDecimal
对象。
基本运算
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = BigDecimal.valueOf(0.9);
System.out.println(a.add(b)); // 加法
System.out.println(a.subtract(b)); // 减法
System.out.println(a.multiply(b)); // 乘法
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP)); // 除法,保留两位小数,四舍五入
浮点数精度问题
- 使用
equals()
比较BigDecimal
时,不仅比较数值,还会比较精度。
超过long的数据表示
超过long(64位)用BigInteger来表示,其内部是用int[]数组来存储任意大小的整型数据
变量
成员变量 vs 局部变量
- 语法形式:成员变量属于类,局部变量是在代码块或方法中定义的变量或者参数;成员变量可以被public,private,static修饰,局部变量不能被访问控制修饰符和ststic,都能被final修饰
- 存储方式:如果成员变量是static修饰的,那么是属于类的,如果没有就是属于实例的。对象存储于堆内存,局部变量存到栈。
- 成员变量如果没有被赋初始值,会自动以类的默认值而赋值(被final修饰的成员变量也必须赋值),局部变量不会自动赋值
变量存储的是内存地址对应的任意随机值,程序读这这个值如果没有默认值会出现意外
静态变量
- 静态变量由类的所有实例共享,且只分配一次内存。可以通过类名或对象访问。
public class StaticVariableExample {
public static int staticVar = 0;
}
静态变量被final修饰会成为常量
public class test{
//常量
public static final int res = 0;
}
静态方法 vs 实例方法
静态方法
- 静态方法属于类,通过类名调用;只能访问静态成员,无法访问实例成员。
- 静态方法在类加载时分配内存。
实例方法
- 实例方法属于对象,必须通过对象调用;可以访问静态成员和实例成员。
方法的重载与重写
方法重载
- 在同一个类中,方法名相同,但参数的类型、个数或顺序不同的称为方法重载。
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder("Hello World");
方法重写
是子类对父类方法的重新改造,外部样子不变,内部逻辑可以改变
- 方法名、参数列表必须相同,子类方法返回值的类型<=父类方法返回值类型,抛出的异常范围<=父类,访问修饰符范围>=父类
- 如果父类方法访问的修饰符为 private/final/static 则子类不能重写方法,但是被static修饰的方法能够被再次声明
- 构造方法无法被重写
ps:如果方法返回值类型是void或基本数据类型,则返回值重写的时候不能修改,但是如果方法的返回值是引用类型,重写时可以返回该引用类型的子类
可变长参数
- 可变长参数可以接受 0 个或多个参数,且必须放在参数列表的最后。
public static void method(String... args) {
// 可变长参数示例
}
静态方法示例
- 静态方法属于类,无法访问实例成员,静态方法在类加载时分配内存。
public static void staticMethod() {
// 静态方法示例
}