Java基础面试题
系统整理Java基础知识的面试题,涵盖Java核心、JVM原理、并发编程等方向,包含详细的答案和解析。
📋 题目分类
🎯 一、Java核心
1. 面向对象三大特性是什么?
答案:
面向对象三大特性是封装、继承、多态。
详细解析:
封装(Encapsulation)
- 将数据和操作数据的方法绑定在一起
- 通过访问修饰符控制访问权限
- 隐藏内部实现细节,提供统一的接口
继承(Inheritance)
- 子类继承父类的属性和方法
- 提高代码复用性
- Java支持单继承,通过接口实现多重继承
多态(Polymorphism)
- 同一个接口,不同的实现
- 方法重写和方法重载
- 运行时多态和编译时多态
2. Java中==和equals的区别?
答案:
- ==:比较的是引用地址,对于基本类型比较的是值
- equals:比较的是对象的内容(需要重写equals方法)
详细解析:
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2); // false,比较引用地址
System.out.println(str1.equals(str2)); // true,比较内容
// String重写了equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}3. final关键字的作用?
答案:
final关键字可以修饰类、方法、变量:
- final类:不能被继承
- final方法:不能被重写
- final变量:不能被修改(常量)
详细解析:
// final类不能被继承
final class FinalClass {
// ...
}
// final方法不能被重写
class Parent {
final void method() {
// ...
}
}
// final变量不能被修改
final int CONSTANT = 100;
final String str = "hello";🎯 二、JVM原理
4. JVM内存区域划分?
答案:
JVM内存区域主要分为以下几个部分:
程序计数器(PC Register)
- 线程私有
- 记录当前线程执行的字节码指令地址
Java虚拟机栈(Java Virtual Machine Stacks)
- 线程私有
- 存储局部变量表、操作数栈、动态链接、方法出口
本地方法栈(Native Method Stack)
- 线程私有
- 为Native方法服务
Java堆(Java Heap)
- 线程共享
- 存储对象实例,垃圾回收的主要区域
- 分为新生代和老年代
方法区(Method Area)
- 线程共享
- 存储类信息、常量、静态变量、编译后的代码
5. 垃圾回收算法有哪些?
答案:
常见的垃圾回收算法有:
标记-清除算法(Mark-Sweep)
- 标记需要回收的对象
- 清除被标记的对象
- 缺点:产生内存碎片
复制算法(Copying)
- 将内存分为两块,每次使用一块
- 将存活对象复制到另一块
- 优点:无碎片;缺点:内存利用率低
标记-整理算法(Mark-Compact)
- 标记需要回收的对象
- 移动存活对象到一端
- 优点:无碎片;缺点:效率较低
分代收集算法
- 根据对象存活周期分为新生代和老年代
- 新生代使用复制算法
- 老年代使用标记-清除或标记-整理算法
6. 什么是类加载机制?
答案:
类加载机制是指将.class文件加载到内存并转换为Class对象的过程。
类加载过程:
加载(Loading)
- 通过类的全限定名获取字节流
- 将字节流转换为方法区的运行时数据结构
- 在内存中生成Class对象
验证(Verification)
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
准备(Preparation)
- 为类变量分配内存
- 设置默认初始值
解析(Resolution)
- 将符号引用转换为直接引用
初始化(Initialization)
- 执行类构造器
<clinit>方法 - 初始化类变量和静态代码块
- 执行类构造器
双亲委派模型:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ...
}
if (c == null) {
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}🎯 三、并发编程
7. synchronized和ReentrantLock的区别?
答案:
区别对比:
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 锁的类型 | JVM层面的锁 | API层面的锁 |
| 锁的释放 | 自动释放 | 需要手动释放 |
| 可中断 | 不可中断 | 可中断 |
| 公平锁 | 非公平锁 | 支持公平锁和非公平锁 |
| 锁的条件 | 只能有一个条件 | 可以有多个条件 |
详细解析:
// synchronized使用
public synchronized void method() {
// ...
}
// ReentrantLock使用
private final ReentrantLock lock = new ReentrantLock();
public void method() {
lock.lock();
try {
// ...
} finally {
lock.unlock();
}
}8. volatile关键字的作用?
答案:
volatile关键字的作用:
保证可见性
- 当一个线程修改了volatile变量,其他线程能立即看到修改
禁止指令重排序
- 编译器不会对volatile变量进行重排序优化
注意:volatile不能保证原子性
详细解析:
public class VolatileExample {
private volatile boolean flag = false;
public void writer() {
flag = true; // 写操作
}
public void reader() {
if (flag) { // 读操作
// ...
}
}
}volatile的实现原理:
- 使用内存屏障(Memory Barrier)
- 写操作后插入Store屏障
- 读操作前插入Load屏障
9. 线程池的原理和使用?
答案:
线程池的核心参数:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:线程空闲时间
- workQueue:工作队列
- threadFactory:线程工厂
- handler:拒绝策略
线程池执行流程:
线程池代码示例:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // corePoolSize
10, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS, // unit
new LinkedBlockingQueue<>(100), // workQueue
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "my-thread-" + System.currentTimeMillis());
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // handler
);🎯 四、集合框架
10. ArrayList和LinkedList的区别?
答案:
区别对比:
| 特性 | ArrayList | LinkedList |
|---|---|---|
| 底层实现 | 动态数组 | 双向链表 |
| 随机访问 | O(1) | O(n) |
| 插入删除 | O(n) | O(1) |
| 内存占用 | 较少 | 较多(需要存储指针) |
| 适用场景 | 随机访问多 | 插入删除多 |
11. HashMap的原理?
答案:
HashMap的核心原理:
数据结构
- JDK 1.8之前:数组+链表
- JDK 1.8之后:数组+链表+红黑树(链表长度>8时转红黑树)
Hash计算
javastatic final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }扩容机制
- 负载因子:0.75
- 扩容时机:size > capacity * loadFactor
- 扩容大小:capacity * 2
put流程
12. HashMap和Hashtable的区别?
答案:
区别对比:
| 特性 | HashMap | Hashtable |
|---|---|---|
| 线程安全 | 非线程安全 | 线程安全(synchronized) |
| 键值null | 允许null键和null值 | 不允许null键和null值 |
| 继承关系 | 继承AbstractMap | 继承Dictionary |
| 迭代器 | Fail-Fast | Fail-Safe |
| 初始容量 | 16 | 11 |
| 扩容机制 | capacity * 2 | capacity * 2 + 1 |
| 性能 | 性能更好 | 性能较差(同步开销) |
建议:
- 多线程环境使用
ConcurrentHashMap替代Hashtable - 单线程环境使用
HashMap
13. ConcurrentHashMap的原理?
答案:
ConcurrentHashMap的核心原理:
JDK 1.7实现
- 使用分段锁(Segment)
- 每个Segment是一个HashMap
- 并发度等于Segment数量
JDK 1.8实现
- 使用数组+链表+红黑树(类似HashMap)
- 使用CAS + synchronized保证线程安全
- 锁粒度更细,性能更好
线程安全机制
java// JDK 1.8使用CAS + synchronized final V putVal(K key, V value, boolean onlyIfAbsent) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = initTable()).length; if ((p = tabAt(tab, i = (n - 1) & hash)) == null) casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)); else { // 使用synchronized锁定链表头节点 synchronized (p) { // ... } } }与HashMap的区别
- 线程安全
- 不允许null键和null值
- 迭代器是弱一致性
14. TreeMap的原理?
答案:
TreeMap的核心原理:
数据结构
- 基于红黑树实现
- 按照key的自然顺序或比较器顺序排序
特点
- 有序的Map集合
- 查询、插入、删除时间复杂度:O(log n)
应用场景
- 需要有序遍历的场景
- 范围查询场景
🎯 五、String和基础类型
15. String、StringBuilder、StringBuffer的区别?
答案:
区别对比:
| 特性 | String | StringBuilder | StringBuffer |
|---|---|---|---|
| 可变性 | 不可变 | 可变 | 可变 |
| 线程安全 | 线程安全(不可变) | 非线程安全 | 线程安全(synchronized) |
| 性能 | 每次操作创建新对象 | 性能最好 | 性能较好(同步开销) |
| 使用场景 | 字符串常量 | 单线程字符串拼接 | 多线程字符串拼接 |
详细解析:
// String是不可变的
String str = "hello";
str = str + " world"; // 创建新对象,原对象被GC回收
// StringBuilder可变
StringBuilder sb = new StringBuilder("hello");
sb.append(" world"); // 修改原对象
// StringBuffer线程安全
StringBuffer sbf = new StringBuffer("hello");
sbf.append(" world"); // synchronized方法,线程安全16. String为什么是不可变的?
答案:
String不可变的原因:
final修饰类
javapublic final class String implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; // ... }final修饰value数组
- value数组是final的,引用不能改变
- 但没有限制数组元素的内容(但String内部没有提供修改方法)
好处
- 安全性:字符串作为参数传递时不会被修改
- 线程安全:多线程环境下安全
- 缓存优化:String Pool可以缓存字符串
- 性能优化:可以缓存hashCode
17. Java基本数据类型有哪些?包装类的作用?
答案:
Java基本数据类型:
| 类型 | 大小 | 包装类 | 默认值 |
|---|---|---|---|
| byte | 1字节 | Byte | 0 |
| short | 2字节 | Short | 0 |
| int | 4字节 | Integer | 0 |
| long | 8字节 | Long | 0L |
| float | 4字节 | Float | 0.0f |
| double | 8字节 | Double | 0.0d |
| char | 2字节 | Character | '\u0000' |
| boolean | 1位 | Boolean | false |
包装类的作用:
在集合中使用
- 集合不能存储基本类型,只能存储对象
提供工具方法
- 类型转换、进制转换等
支持泛型
- 泛型不支持基本类型
值缓存
- Integer缓存-128到127的值
- 相同的值可能指向同一个对象
自动装箱和拆箱:
// 自动装箱:基本类型 -> 包装类
Integer i = 100; // 相当于 Integer.valueOf(100)
// 自动拆箱:包装类 -> 基本类型
int j = i; // 相当于 i.intValue()18. 基本类型和包装类的区别?
答案:
区别对比:
| 特性 | 基本类型 | 包装类 |
|---|---|---|
| 存储位置 | 栈内存 | 堆内存 |
| 默认值 | 有默认值 | null |
| 内存占用 | 较小 | 较大 |
| 性能 | 性能更好 | 性能较差 |
| 使用场景 | 局部变量、数组 | 集合、泛型、作为对象传递 |
🎯 六、异常处理
19. Java异常体系?
答案:
Java异常体系:
异常分类:
Error
- 系统错误,不应该捕获
- 如:OutOfMemoryError、StackOverflowError
RuntimeException(运行时异常)
- 非检查异常,不需要声明
- 如:NullPointerException、IllegalArgumentException
CheckedException(检查异常)
- 检查异常,必须处理
- 如:IOException、SQLException
20. try-catch-finally的执行顺序?
答案:
执行顺序:
try块
- 执行正常代码
catch块
- 捕获异常并处理
finally块
- 无论是否异常都会执行
- 通常用于资源释放
注意事项:
// finally中的return会覆盖try和catch中的return
public int test() {
try {
return 1;
} catch (Exception e) {
return 2;
} finally {
return 3; // 最终返回3
}
}
// finally在return之前执行
public int test2() {
int i = 0;
try {
return i; // 先计算返回值i=0,保存起来
} finally {
i++; // 执行finally,i=1,但不影响返回值
}
// 最终返回0
}🎯 七、反射机制
21. 什么是反射?反射的应用场景?
答案:
反射(Reflection):在运行时动态获取类的信息并操作类的能力。
反射的应用场景:
框架开发
- Spring的IoC容器
- MyBatis的Mapper映射
- JPA的实体映射
动态代理
- JDK动态代理使用反射
注解处理
- 运行时处理注解
工具类
- 对象的序列化/反序列化
反射的优缺点:
优点:
- 运行时动态获取类信息
- 灵活性高
缺点:
- 性能开销大
- 安全性问题(绕过访问控制)
- 代码可读性差
反射示例:
// 获取Class对象
Class<?> clazz = Class.forName("com.example.User");
// 创建实例
Object obj = clazz.newInstance();
// 获取方法
Method method = clazz.getMethod("setName", String.class);
// 调用方法
method.invoke(obj, "张三");
// 获取字段
Field field = clazz.getDeclaredField("name");
field.setAccessible(true); // 设置可访问
field.set(obj, "李四");🎯 八、IO/NIO
22. BIO、NIO、AIO的区别?
答案:
区别对比:
| 特性 | BIO | NIO | AIO |
|---|---|---|---|
| 阻塞方式 | 阻塞IO | 非阻塞IO | 异步IO |
| 连接模型 | 一个连接一个线程 | 一个线程处理多个连接 | 异步操作,无需线程等待 |
| 适用场景 | 连接数少 | 连接数多、短连接 | 连接数多、长连接 |
| 同步方式 | 同步阻塞 | 同步非阻塞 | 异步非阻塞 |
详细解析:
BIO(Blocking IO)
java// 阻塞IO,一个连接一个线程 ServerSocket serverSocket = new ServerSocket(8080); Socket socket = serverSocket.accept(); // 阻塞NIO(Non-blocking IO)
java// 非阻塞IO,一个线程处理多个连接 ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); // 非阻塞模式 Selector selector = Selector.open(); serverChannel.register(selector, SelectionKey.OP_ACCEPT);AIO(Asynchronous IO)
java// 异步IO AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(); serverChannel.bind(new InetSocketAddress(8080)); serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() { // 异步处理 });
23. NIO的核心组件?
答案:
NIO的核心组件:
Channel(通道)
- 双向的数据通道
- 常见实现:FileChannel、SocketChannel、ServerSocketChannel
Buffer(缓冲区)
- 数据容器
- 常见实现:ByteBuffer、CharBuffer、IntBuffer
Selector(选择器)
- 多路复用器
- 一个线程管理多个Channel
NIO工作流程:
🎯 九、并发工具类
24. CAS(Compare-And-Swap)的原理?
答案:
CAS(Compare-And-Swap):比较并交换,是一种无锁算法。
CAS原理:
操作步骤
- 读取内存值V
- 比较V和期望值A
- 如果相等,写入新值B
- 如果不相等,重新尝试
原子性保证
- CPU提供原子指令(如CMPXCHG)
- 一条指令完成比较和交换
CAS的优缺点
优点:
- 无锁编程,性能好
- 避免了锁的开销
缺点:
- ABA问题(可以使用版本号解决)
- 自旋时间长消耗CPU
- 只能保证一个变量的原子性
CAS示例:
// AtomicInteger内部使用CAS
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
// Unsafe类的CAS操作
public final native boolean compareAndSwapInt(
Object o, long offset, int expected, int x);25. AQS(AbstractQueuedSynchronizer)的原理?
答案:
AQS(AbstractQueuedSynchronizer):抽象队列同步器,是Java并发包的基础。
AQS核心原理:
核心组件
- state:同步状态
- CLH队列:等待队列(双向链表)
工作流程
AQS的使用
- ReentrantLock
- CountDownLatch
- Semaphore
- CyclicBarrier
AQS示例:
// ReentrantLock使用AQS
public class ReentrantLock implements Lock {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
// 实现tryAcquire、tryRelease等方法
}
}26. CountDownLatch、CyclicBarrier、Semaphore的区别?
答案:
区别对比:
| 特性 | CountDownLatch | CyclicBarrier | Semaphore |
|---|---|---|---|
| 用途 | 等待多个线程完成 | 多个线程相互等待 | 控制并发数 |
| 计数 | 一次性,计数递减 | 可重用,计数递增 | 可重用,计数递减 |
| 阻塞线程 | 一个或多个线程等待 | 所有线程相互等待 | 获取许可的线程被阻塞 |
| 重置 | 不能重置 | 可以重置 | 不能重置 |
使用场景:
CountDownLatch
javaCountDownLatch latch = new CountDownLatch(3); // 3个线程完成后,主线程继续 latch.await();CyclicBarrier
javaCyclicBarrier barrier = new CyclicBarrier(3); // 3个线程都到达后,同时继续 barrier.await();Semaphore
javaSemaphore semaphore = new Semaphore(3); // 最多3个线程同时执行 semaphore.acquire(); // ... semaphore.release();
🎯 十、垃圾回收器
27. 常见的垃圾回收器有哪些?
答案:
常见的垃圾回收器:
Serial GC
- 单线程GC
- 适合单核CPU、小内存应用
Parallel GC
- 多线程GC
- 吞吐量优先
- 适合后台应用
CMS(Concurrent Mark Sweep)
- 并发标记清除
- 低延迟优先
- JDK 9标记为废弃
G1(Garbage First)
- 分区收集
- 低延迟、高吞吐
- JDK 9默认GC
ZGC
- 超低延迟
- 适合大内存应用
- JDK 11引入
Shenandoah
- 低延迟GC
- 适合大内存应用
GC选择建议:
- 小应用:Serial GC
- 后台应用:Parallel GC
- Web应用:G1 GC
- 大内存应用:ZGC或Shenandoah
28. G1垃圾回收器的特点?
答案:
G1(Garbage First)的特点:
分区设计
- 将堆分为多个Region
- 每个Region可以独立回收
优先级回收
- 优先回收垃圾最多的Region
- 提高回收效率
可预测的停顿时间
- 通过控制回收时间,达到可预测的停顿
并发标记
- 并发标记阶段不停止应用线程
- 减少停顿时间
G1工作流程:
🎯 十一、JVM调优
29. JVM调优的常用参数?
答案:
常用JVM参数:
堆内存参数
bash-Xms2g # 初始堆大小 -Xmx2g # 最大堆大小 -Xmn1g # 新生代大小 -XX:SurvivorRatio=8 # Eden和Survivor比例方法区参数
bash-XX:MetaspaceSize=256m # 元空间初始大小 -XX:MaxMetaspaceSize=512m # 元空间最大大小GC参数
bash-XX:+UseG1GC # 使用G1 GC -XX:MaxGCPauseMillis=200 # 最大GC停顿时间 -XX:+PrintGCDetails # 打印GC详情 -XX:+HeapDumpOnOutOfMemoryError # OOM时生成堆转储其他参数
bash-XX:+PrintGCDetails # 打印GC详情 -XX:+HeapDumpOnOutOfMemoryError # OOM时生成堆转储 -Xss256k # 线程栈大小
30. 如何排查内存溢出问题?
答案:
排查步骤:
查看GC日志
bash-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log生成堆转储文件
bash-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heapdump.hprof使用jmap命令
bashjmap -heap <pid> # 查看堆内存使用情况 jmap -histo <pid> # 查看对象统计 jmap -dump:format=b,file=heap.hprof <pid> # 导出堆转储使用jvisualvm分析
- 打开堆转储文件
- 查看内存占用最多的对象
- 分析对象引用关系
常见原因
- 内存泄漏(对象未释放)
- 对象过大(大数组、大字符串)
- 线程过多(线程栈内存占用)
🎯 十二、Java新特性
31. Lambda表达式和Stream API?
答案:
Lambda表达式:
- 简化匿名内部类的写法
- 函数式编程的支持
示例:
// 传统写法
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Lambda写法
Runnable r = () -> System.out.println("Hello");
// 方法引用
List<String> list = Arrays.asList("a", "b", "c");
list.forEach(System.out::println);Stream API:
- 函数式编程风格
- 链式调用
- 延迟执行
示例:
List<String> list = Arrays.asList("a", "bb", "ccc", "dddd");
// 过滤长度>2的字符串,转换为大写,排序
list.stream()
.filter(s -> s.length() > 2)
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);32. Java 8新特性有哪些?
答案:
Java 8主要新特性:
Lambda表达式
- 函数式编程支持
Stream API
- 集合操作API
方法引用
- 简化Lambda表达式
默认方法
- 接口可以有默认实现
Optional
- 避免空指针异常
新的日期时间API
- LocalDate、LocalTime、LocalDateTime
CompletableFuture
- 异步编程支持
示例:
// Optional使用
Optional<String> optional = Optional.ofNullable(str);
String value = optional.orElse("default");
// 新日期API
LocalDate date = LocalDate.now();
LocalDateTime dateTime = LocalDateTime.now();🎯 十三、其他重要知识点
33. hashCode和equals方法的关系?
答案:
hashCode和equals的契约:
- 如果两个对象equals相等,hashCode必须相等
- 如果两个对象hashCode相等,equals不一定相等
- 如果两个对象hashCode不相等,equals一定不相等
为什么需要重写hashCode?
- HashMap等集合使用hashCode定位bucket
- 如果equals相等但hashCode不相等,可能导致HashMap找不到对象
重写示例:
public class User {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}34. 如何实现对象的深拷贝?
答案:
深拷贝的实现方式:
实现Cloneable接口
javapublic class User implements Cloneable { private String name; private Address address; @Override public Object clone() throws CloneNotSupportedException { User user = (User) super.clone(); user.address = (Address) address.clone(); // 深度拷贝 return user; } }使用序列化
javapublic static <T> T deepClone(T obj) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(obj); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (T) ois.readObject(); }使用JSON序列化
java// 使用Gson或Jackson Gson gson = new Gson(); String json = gson.toJson(obj); return gson.fromJson(json, obj.getClass());
35. 内部类的类型和作用?
答案:
内部类的类型:
成员内部类
- 定义在类内部
- 可以访问外部类的成员
- 不能有静态成员(静态内部类除外)
静态内部类
- 使用static修饰
- 不能访问外部类的非静态成员
- 可以有静态成员
局部内部类
- 定义在方法内部
- 只能访问final局部变量
匿名内部类
- 没有类名
- 通常用于实现接口或继承类
使用场景:
- 实现回调
- 隐藏实现细节
- 简化代码结构
示例:
// 静态内部类
public class Outer {
private static int count = 10;
static class Inner {
public void show() {
System.out.println(count); // 可以访问静态成员
}
}
}
// 匿名内部类
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};📖 学习资源
视频教程
书籍推荐
- 《Java核心技术》 - Cay S. Horstmann
- 《深入理解Java虚拟机》 - 周志明
- 《Java并发编程实战》 - Brian Goetz
网站资源
📚 总结
Java基础面试题涵盖了Java开发的各个方面,包括:
- Java核心:面向对象、String、基本类型、包装类、异常处理、反射
- JVM原理:内存模型、垃圾回收、类加载、JVM调优
- 并发编程:线程、锁、并发工具类、线程池
- 集合框架:ArrayList、LinkedList、HashMap、ConcurrentHashMap
- IO/NIO:BIO、NIO、AIO的区别和应用
- Java新特性:Lambda、Stream、Optional等
掌握这些知识点,能够更好地应对Java开发中的各种挑战。
✅ 学习检查清单
- [ ] 已掌握Java面向对象特性
- [ ] 已理解String和基本类型
- [ ] 已掌握异常处理机制
- [ ] 已理解反射机制
- [ ] 已理解JVM内存模型
- [ ] 已掌握垃圾回收机制
- [ ] 已理解类加载机制
- [ ] 已掌握垃圾回收器和JVM调优
- [ ] 已掌握并发编程(线程、锁、并发工具类)
- [ ] 已理解CAS和AQS原理
- [ ] 已熟悉集合框架(ArrayList、HashMap、ConcurrentHashMap)
- [ ] 已理解IO/NIO的区别
- [ ] 已了解Java新特性(Lambda、Stream)
- [ ] 已练习常见面试题
- [ ] 已总结答题技巧
上一章节:面试题概览
下一章节:Spring框架面试题
返回目录:面试题