对于初学者来说,掌握Java的基础知识是成为一名优秀Java开发者的第一步。而对于经验丰富的开发者,扎实的基础同样是继续深入学习、攻克更高难度技术的基础。因此,在面试和实际工作中,Java的基础知识不仅是评估开发者能力的标准,也是编程思维和问题解决能力的体现。
通过本文章学习,你不仅能够增强自己的Java编程基础,还能熟悉常见的面试题目,做好应对技术面试的准备。无论你是刚刚接触Java的新人,还是有一定经验的开发者,本文章都将为你提供扎实的基础与灵感,帮助你在Java的道路上走得更远。
Java中的数据类型分为基本数据类型和引用数据类型。
整数型:byte、short、int、long;布尔型:boolean;字符型:char;浮点型:float、double
数组Array、接口Interface、类(String等),注意String不是基本数据类型
Java的自动装箱就是将基本数据类型转化为对应的封装类;自动拆箱就是封装类转化为对应的基本数据类型;
不可变类是指在创建后其状态、数据就无法被修改的类,这种类的实例在整个生命周期内保持不变。特性如下:
常见的不可变类有String、Integer等,当我们对String对拼接、剪切等操作,都是新建一个String对象并指向它。
定义:同一操作作用于不同对象时产生不同行为,分为:
void print(int a) { ... }
void print(String s) { ... } // 重载
class Animal { void sound() { ... } }
class Dog extends Animal {
@Override void sound() { ... } // 重写
}
应用场景:接口回调、框架设计(如Spring依赖注入)。
核心思想:隐藏对象内部细节,通过公共方法控制访问。
private
修饰属性,提供public getter/setter
。private
。示例:
class Person {
private int age;
public void setAge(int age) {
if (age >= 0) this.age = age; // 数据校验
}
}
定义:子类继承父类的属性和方法,实现代码复用和层次化设计。
class Sub extends Super { ... }
@Override
)。private
成员不可直接访问。示例:
class Vehicle { void run() { ... } }
class Car extends Vehicle {
@Override void run() { ... } // 重写父类方法
}
根本原因:避免菱形继承问题(多个父类有同名方法时冲突)。
implements Interface1, Interface2
)实现多重能力扩展。Runnable
和Serializable
接口组合)。序列化:将对象转换为字节流(网络传输或持久化存储)。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data.obj"));
oos.writeObject(obj); // 序列化
反序列化:将字节流恢复为对象。
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.obj"));
MyClass obj = (MyClass) ois.readObject(); // 反序列化
注意事项:
Serializable
接口(标记接口)。transient
关键字修饰不序列化的字段。特性 | 重写(Override) | 重载(Overload) |
---|---|---|
作用范围 | 父子类之间 | 同一类中 |
方法签名 | 必须相同(方法名、参数、返回类型) | 方法名相同,参数列表不同 |
访问权限 | 子类方法不能更严格(如父类protected ,子类不能为private ) |
无限制 |
抛出异常 | 子类异常范围 ≤ 父类 | 无限制 |
示例:
// 重写
class Parent { void doSomething() throws IOException { ... } }
class Child extends Parent {
@Override void doSomething() throws FileNotFoundException { ... } // 异常范围更小
}
// 重载
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; } // 参数类型不同
}
类别 | Exception(异常) | Error(错误) |
---|---|---|
可恢复性 | 程序可捕获并处理(如文件未找到) | JVM系统级错误,程序无法恢复(如内存溢出) |
处理方式 | 需try-catch 或throws 声明 |
通常不处理,由JVM终止程序 |
常见子类 | IOException , SQLException |
OutOfMemoryError , StackOverflowError |
维度 | 面向对象(OOP) | 面向过程(POP) |
---|---|---|
核心思想 | 对象为中心,关注数据与行为的结合 | 函数为中心,关注步骤执行顺序 |
代码复用 | 继承、组合 | 函数复用 |
典型语言 | Java、C++ | C、Pascal |
适用场景 | 复杂系统设计(如企业级应用) | 简单逻辑或性能敏感场景(如嵌入式) |
Java严格按值传递:
void change(int x) { x = 10; }
int a = 5;
change(a); // a仍为5
void changeName(Student s) {
s.setName("Bob"); // 修改对象内容,原对象受影响
s = new Student(); // 重新赋值,原引用不变
}
作用:
Iterator
的内部类)。分类:
class Outer {
class Inner { ... }
}
class Outer {
static class StaticInner { ... }
}
Runnable r = new Runnable() { // 匿名内部类
public void run() { ... }
};
特性 | String | StringBuilder | StringBuffer |
---|---|---|---|
可变性 | 不可变(final char[]) | 可变 | 可变 |
线程安全 | 线程安全(不可变) | 非线程安全 | 线程安全(synchronized方法) |
性能 | 低(频繁拼接产生新对象) | 高 | 中等(同步开销) |
适用场景 | 常量或少量拼接 | 单线程下大量字符串操作 | 多线程下字符串操作 |
示例:
String s1 = "a" + "b"; // 编译优化为"ab",只生成一个对象
StringBuilder sb = new StringBuilder();
sb.append("a").append("b"); // 直接修改内部数组
特性 | 接口(Interface) | 抽象类(Abstract Class) |
---|---|---|
实现方式 | 多实现(implements A, B ) |
单继承(extends ) |
构造方法 | 无 | 有(用于子类初始化) |
方法类型 | Java 8前:全抽象;Java 8+:可含默认/静态方法 | 可包含抽象和具体方法 |
字段修饰符 | 默认public static final |
无限制 |
设计目的 | 定义行为契约(如Comparable ) |
提供通用实现(如AbstractList ) |
java.lang
),用于运行Java程序。javac
编译器、jar
打包工具、调试器等)。equals
方法)。HashMap
)快速查找。a.equals(b) == true
,则a.hashCode() == b.hashCode()
。hashCode
冲突时,哈希表通过链表或红黑树处理。示例:
class Student {
String id;
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student s = (Student) o;
return id.equals(s.id); // 根据id判断相等
}
public int hashCode() {
return id.hashCode(); // 保证相同id的hashCode一致
}
}
定义:在运行时动态生成代理类,增强目标对象功能(如日志、事务)。
InvocationHandler
和Proxy
类实现。 interface Subject { void request(); }
class RealSubject implements Subject { ... }
InvocationHandler handler = (proxy, method, args) -> {
System.out.println("Before method");
return method.invoke(new RealSubject(), args);
};
Subject proxy = (Subject) Proxy.newProxyInstance(
loader, new Class[]{Subject.class}, handler);
cglib
库)。特性 | JDK动态代理 | CGLIB代理 |
---|---|---|
依赖 | 目标类需实现接口 | 无接口要求(通过继承) |
性能 | 调用方法较慢(反射) | 生成代理类较慢,调用方法较快 |
限制 | 无法代理final类/方法 | 无法代理final方法 |
实现方式 | Proxy + InvocationHandler |
ASM字节码操作生成子类 |
定义:在运行时获取类信息并动态操作对象(如创建实例、调用方法)。
Class
、Field
、Method
、Constructor
。示例:
Class> clazz = Class.forName("com.example.MyClass");
Object obj = clazz.newInstance(); // 创建实例
Method method = clazz.getMethod("methodName");
method.invoke(obj); // 调用方法
机制:服务提供者动态加载实现类,解耦接口与实现。
java.sql.Driver
)。META-INF/services/
下创建以接口全限定名命名的文件。com.mysql.jdbc.Driver
)。List
只能存字符串)。ClassCastException
风险。Comparator
)。示例:
List list = new ArrayList<>(); // 泛型定义
list.add("Hello");
// list.add(1); // 编译报错
定义:编译器在编译后移除泛型类型信息,替换为原始类型(如List
→List
)。
T.class
非法)。TypeToken
(如Gson库)获取泛型类型。示例:
List list = new ArrayList<>();
list.add(1);
// 编译后等同于:
List list = new ArrayList();
list.add(1);
class Person implements Cloneable {
Address address; // 引用类型
public Object clone() { return super.clone(); } // 浅拷贝
}
public Object clone() {
Person p = (Person) super.clone();
p.address = (Address) address.clone(); // 递归拷贝引用对象
return p;
}
范围:-128到127的Integer
对象会被缓存(通过IntegerCache
)。
示例:
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(从缓存获取)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(new新对象)
.class
二进制数据,生成Class
对象。int
默认为0)。
方法)。双亲委派:类加载请求先委派父加载器处理,避免重复加载。
作用:精确计算浮点数(避免0.1 + 0.2 ≠ 0.3
问题)。
String
参数(避免double
精度丢失)。BigDecimal d1 = new BigDecimal("0.1");
BigDecimal d2 = new BigDecimal("0.2");
System.out.println(d1.add(d2)); // 0.3
add()
, subtract()
, multiply()
, divide()
(需指定舍入模式)。new
的堆对象。String
)。try-catch
中无论是否异常都会执行的代码块(常用于释放资源)。Object
类方法,对象被GC回收前调用(不推荐依赖,可用try-with-resources
替代)。-Dfile.encoding=UTF-8
。改动:将内部char[]
改为byte[]
+ 编码标记(coder
)。
优势:
结果:抛出IllegalThreadStateException
。
原因:线程状态从NEW
变为RUNNABLE
后不可逆。
正确用法:一个线程实例只能调用一次start()
。
特性 | 队列(Queue) | 栈(Stack) |
---|---|---|
结构 | FIFO(先进先出) | LIFO(后进先出) |
方法 | add() , remove() |
push() , pop() |
实现类 | LinkedList , PriorityQueue |
Stack , Deque (推荐用ArrayDeque ) |
InputStream
(如FileInputStream
)。OutputStream
(如FileOutputStream
)。Reader
(如FileReader
)。Writer
(如FileWriter
)。缓冲流:BufferedInputStream
、BufferedReader
(提升读写性能)。
作用:提供统一遍历集合元素的方式,隐藏底层实现。
hasNext()
:是否还有元素。next()
:返回下一个元素。remove()
:删除当前元素。ConcurrentModificationException
(如ArrayList
)。示例:
List list = new ArrayList<>();
Iterator it = list.iterator();
while (it.hasNext()) {
String s = it.next();
it.remove(); // 安全删除
}
特性 | 运行时异常(RuntimeException) | 编译时异常(Checked Exception) |
---|---|---|
处理要求 | 可不处理(通常为逻辑错误) | 必须try-catch 或throws 声明 |
常见异常 | NullPointerException , IndexOutOfBoundsException |
IOException , ClassNotFoundException |
修饰符 | 同类 | 同包 | 子类 | 其他包 |
---|---|---|---|---|
private |
✔ | ✖ | ✖ | ✖ |
default |
✔ | ✔ | ✖ | ✖ |
protected |
✔ | ✔ | ✔ | ✖ |
public |
✔ | ✔ | ✔ | ✔ |
ConcurrentModificationException
(除非使用迭代器的remove()
)。示例:
// for循环删除元素(安全)
for (int i = 0; i < list.size(); i++) {
if (condition) list.remove(i--);
}
// foreach循环删除元素(抛异常)
for (String s : list) {
list.remove(s); // 错误!
}
流程:类加载器收到加载请求后,依次向上委托给父加载器,若父类无法加载,才由子类加载。
层级:
JRE/lib
核心类(如rt.jar
)。JRE/lib/ext
扩展类。-classpath
)。破坏场景:
java.lang.String
无效)。特性 | wait() | sleep() |
---|---|---|
所属类 | Object |
Thread |
锁释放 | 释放锁 | 不释放锁 |
调用条件 | 必须在同步块中(持有锁) | 任意位置 |
唤醒方式 | notify() /notifyAll() |
时间到自动唤醒 |
异常 | 可能抛InterruptedException |
同左 |
定义:Java源代码编译后的中间代码(.class
文件),由JVM解释执行。
优势:跨平台(不同平台JVM解释相同字节码)。
查看工具:javap -c MyClass.class
反编译字节码。
特性 | 静态方法 | 实例方法 |
---|---|---|
调用方式 | 类名调用(Math.abs() ) |
对象调用(list.add() ) |
访问权限 | 只能访问静态成员 | 可访问静态和实例成员 |
内存分配 | 类加载时分配内存 | 对象实例化后分配 |
重写 | 不可被重写(隐藏) | 可被重写 |
目的:显式处理null
,避免空指针异常。
核心方法:
Optional.ofNullable(value)
:包装可能为null
的值。orElse(default)
:值为空时返回默认值。orElseThrow()
:值为空时抛异常。示例:
Optional name = Optional.ofNullable(user.getName());
String result = name.orElse("Unknown");
char[]
数组(默认容量16)。原容量*2 + 2
。StringBuffer
通过synchronized
保证安全)。示例:
StringBuilder sb = new StringBuilder();
sb.append("a"); // 容量足够时直接追加
sb.append("bcd"); // 触发扩容