饿了么Java面试经验分享:从基础知识到项目实战的全方位指南
今天分享的是来自华中师范大学的一位同学的饿了么Java一面面经,主要考察Java基础知识以及项目经验(例如黑马点评),内容相对简单。
1. Java基础的核心模块概述
以下是我认为Java基础知识比较核心的模块总结:
- 异常处理:定义了Java运行中可能出现的异常,并提供了处理机制。
- 泛型:通过使用泛型参数,提高代码的可读性和稳定性。
- 反射机制:允许在运行时对类进行分析,并执行类中的方法,可以获取任意类的属性和方法,并调用它们。
- 注解:可以视作一种特殊的注释,主要用于修饰类、方法或变量,提供信息供编译或运行时使用。
- 集合框架:Java集合,也称为容器,用于保存数据,主分为List、Set、Queue和Map四大类,每类有不同的用途。
- 输入输出流(I/O):用于处理输入和输出操作,例如文件读写。
- 多线程:除了基础的
Thread
类和Runnable
接口外,最重要的就是Java并发工具包(JUC),其中包含了并发编程中常用的工具类,如线程池、异步I/O、各种锁等。
2. Java异常的顶层结构及接口实现
Java异常类层次结构概览:
![图片](data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='1px' height='1px' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' fill-opacity='0'%3E%3Cg transform='translate(-249.000000, -126.000000)' fill='%23FFFFFF'%3E%3Crect x='249' y='126' width='1' height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
在Java中,所有的异常类都继承自java.lang
包中的Throwable
类。Throwable
类有两个重要的子类:
Exception
:程序可以处理的异常,通过catch
捕获。可以分为检查异常(Checked Exception)和非检查异常(Unchecked Exception)。Error
:这些是程序无法处理的错误,通常不建议通过catch
捕获,例如Java虚拟机运行错误和内存不足错误。
3. Java集合的顶层结构及接口实现
Java集合框架架构图如下:
![图片](data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='1px' height='1px' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' fill-opacity='0'%3E%3Cg transform='translate(-249.000000, -126.000000)' fill='%23FFFFFF'%3E%3Crect x='249' y='126' width='1' height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
具体的集合接口实现类如下:
List接口实现类:
ArrayList
:基于动态数组实现。LinkedList
:基于双向链表实现。Vector
:与ArrayList
类似,但提供线程安全性。Stack
:继承自Vector
,实现栈的功能。
Set接口实现类:
HashSet
:基于哈希表实现,元素无序。LinkedHashSet
:结合哈希表和链表,维护插入顺序。TreeSet
:基于红黑树实现,元素有序。
Map接口实现类:
HashMap
:存储键值对,早期基于数组和链表实现。LinkedHashMap
:维护插入顺序的HashMap
,效率更高。TreeMap
:提供基于键的排序功能。Hashtable
:与HashMap
相似,但线程安全。
Queue接口实现类:
LinkedList
:同时实现了List
和Queue
接口。PriorityQueue
:元素出队顺序依据优先级。ArrayDeque
:基于动态数组和双指针实现,允许在两端进行操作。
4. HashMap的结构分析
JDK1.8之前
在JDK1.8之前,HashMap
底层结构结合了数组和链表,也称为链表散列。通过key
的hashcode
计算哈希值,并通过(n - 1) & hash
确定存放位置。如果位置已有元素,通过键值比较解决冲突。
扰动函数是HashMap的hash
方法,用于降低碰撞几率。
JDK 1.8的hash
方法源码如下:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
JDK 1.7的hash
方法源码如下:
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
5. IO流的基本概念
在Java中,I/O代表输入和输出。输入是将数据传入计算机的过程,而输出则是将数据从计算机输出到外部存储(如文件、数据库等)。I/O流被分为输入流和输出流,依据处理方式又分为字节流和字符流。
Java中的I/O流类大多源自以下四个抽象类:
InputStream
/Reader
: 输入流基类。OutputStream
/Writer
: 输出流基类。
6. 字节流与字符流的区别
尽管信息的存储最小单元为字节,但I/O操作分为字节流和字符流主要有两点原因:
- 字符流是将字节转换为字符的过程,效率较低。
- 使用字节流时对编码方式不明时,可能会出现乱码。
7. 使用Redis的原因
在面试时,您可以从“高性能”和“高并发”这两个方面来回答。
高性能:对于高频且不常改变的数据,可以将其缓存以提高再次访问的速度。
高并发:使用Redis可以显著提高QPS(每秒查询次数),例如Redis可达到10w+的QPS,远高于传统数据库。
8. Redis与MySQL的流量承受能力
如上所述,Redis在流量承受能力上显著高于MySQL。
9. Redis的数据结构及底层实现
Redis常见的数据类型包括:
- 基础数据类型:String、List、Set、Hash、Zset。
- 特殊数据类型:HyperLogLog、Bitmap、Geospatial。
这些基础数据类型的底层数据结构实现主要依赖:简单动态字符串、双向链表、哈希表、跳跃表等。
10. 使用MQ的理由
使用消息队列可以带来以下优势:
- 提高系统性能,减少响应时间。
- 实现削峰与限流。
- 降低系统耦合性。
11. 消息队列的解耦示例
通过消息队列,生产者和消费者之间的耦合性降低,系统的可扩展性增强。
![图片](data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='1px' height='1px' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' fill-opacity='0'%3E%3Cg transform='translate(-249.000000, -126.000000)' fill='%23FFFFFF'%3E%3Crect x='249' y='126' width='1' height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
12. 如何创建线程?
在Java中,创建线程的方式有多种,例如继承Thread
类、实现Runnable
接口等,但最终仍依赖于new Thread().start()
。
13. 线程池的参数解析
ThreadPoolExecutor
的重要参数包括:
corePoolSize
:最大同时运行的线程数量。maximumPoolSize
:任务队列满时的最大线程数量。workQueue
:任务被存放的队列。
![图片](data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='1px' height='1px' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' fill-opacity='0'%3E%3Cg transform='translate(-249.000000, -126.000000)' fill='%23FFFFFF'%3E%3Crect x='249' y='126' width='1' height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)
在任务队列未满时,最多运行的线程数量为核心线程数;当任务队列满时,最多运行的线程数量为最大线程数。