目录
一、基础类型与字面量(1-10)#
int 最大值 2,147,483,647(2³¹-1),最小值 -2,147,483,648(-2³¹)
long 最大值 9,223,372,036,854,775,807(2⁶³-1),字面量加 L
float 字面量必须加 f,否则默认 double
short 范围 -32,768 ~ 32,767,byte 范围 -128 ~ 127
- 字面量下划线:
1_000_000 等于 1000000,仅 Java 7+
0x 开头是十六进制,0b 开头是二进制,0 开头是八进制(容易误判)
char 占 2 字节,Character.SIZE = 16,但 Unicode 扩展字符需 2 个 char(surrogate pair)
boolean 只有 true/false,不能和 0/1 互转(和 C 不同)
Integer.valueOf(127) == Integer.valueOf(127) 为 true,128 为 false(缓存池 -128~127)
Integer.parseInt("") 抛 NumberFormatException,Integer.parseInt(null) 也抛
二、运算符与表达式(11-18)#
& 和 && 区别:& 两边都执行(位运算或逻辑与),&& 短路
| 和 || 同理,|| 短路
^ 按位异或,~ 按位取反(包含符号位)
>> 算术右移(补符号位),>>> 无符号右移(补 0)
i++ 和 ++i 的字节码区别:前者先加载后自增,后者先自增后加载
+= 隐式类型转换:short s = 1; s += 1; 合法,s = s + 1; 编译错误
- 三元运算符
? : 必须返回相同类型,否则自动类型提升
- 字符串拼接用
+ 在循环内会生成大量 StringBuilder,循环外编译器自动优化
三、String 相关(19-28)#
String 不可变,底层 char[] 被 final 修饰且不暴露修改方法
- 字符串常量池在堆中(Java 8+),
intern() 手动入池
new String("abc") 创建 2 个对象(常量池 + 堆),"abc" 只创建 1 个(若池中没有)
String.equals() 比较内容,== 比较引用地址
String.compareTo() 按字典序比较,返回差值
String.format() 使用 %s %d %f 占位符
substring() 在 Java 7 前共享 char[],Java 7+ 创建新数组(解决内存泄漏)
split() 参数是正则,. 需转义为 \\.
replace() 替换所有字符,replaceAll() 支持正则
StringBuilder 线程不安全,StringBuffer 线程安全(方法加 synchronized),但慢
四、equals 与 hashCode(29-34)#
- 重写
equals 必须重写 hashCode,否则 HashMap/HashSet 失效
equals 必须满足:自反、对称、传递、一致、非空(x.equals(null) 返回 false)
hashCode 相等的两个对象 equals 不一定相等(哈希冲突)
Objects.equals(a, b) 自动判空,避免 null.equals()
Arrays.deepEquals() 比较多维数组,Arrays.equals() 只比较一维
List.equals() 要求顺序相同,Set.equals() 仅要求元素相同(顺序无关)
五、异常处理(35-44)#
try-catch-finally 中 finally 在 return 之前执行,但返回值已在 finally 前计算好
finally 中有 return 会覆盖 try/catch 的返回值
finally 中修改返回的引用对象内容会生效(如 List.add())
- 不要在
finally 中写 return,也不要在其中抛出异常(会掩盖原始异常)
try-with-resources 要求资源实现 AutoCloseable,关闭顺序:先声明的后关闭
- 受检异常(
Exception 子类)必须 try-catch 或 throws,RuntimeException 非受检
- 异常链:
catch (SQLException e) { throw new RuntimeException(e); } 保留堆栈
printStackTrace() 不应用在生产日志中,用 log.error("msg", e)
Throwable 包括 Error 和 Exception,Error 不应该捕获(如 OutOfMemoryError)
finally 中关闭资源时可能抛异常,要用 try-catch 包裹或使用 try-with-resources
六、集合框架(45-62)#
ArrayList 初始容量 10,扩容 1.5 倍(oldCapacity + (oldCapacity >> 1))
ArrayList 随机访问 O(1),中间插入删除 O(n),LinkedList 相反
LinkedList 实现了 Deque,可作为队列/栈使用
HashMap 容量为 2 的幂,默认 16,负载因子 0.75,扩容 2 倍
HashMap 索引计算:(n - 1) & hash,hash = key.hashCode() ^ (h >>> 16)
- Java 8+
HashMap 链表长度 > 8 且容量 >= 64 时转红黑树,< 6 时退化为链表
HashMap 的 key 为 null 时,hash 值为 0,存在 table[0]
ConcurrentHashMap 分段锁(Java 7)→ synchronized + CAS(Java 8+)
Hashtable 线程安全但全表锁,已淘汰
TreeMap 基于红黑树,有序(按 key 自然序或 Comparator)
LinkedHashMap 按插入顺序或访问顺序(accessOrder=true 可实现 LRU)
HashSet 底层是 HashMap,TreeSet 底层是 TreeMap
PriorityQueue 小顶堆,Comparator.reverseOrder() 可转大顶堆
ArrayDeque 优于 Stack(Stack 已废弃,ArrayDeque 线程不安全但更快)
Collections.synchronizedList() 包装为线程安全,但迭代时仍需手动同步
CopyOnWriteArrayList 读多写少场景,写时复制整个数组
List.of() / Set.of()(Java 9+)返回不可变集合,不能增删改
ArrayList.subList() 返回视图,对子列表操作会影响原列表,反之亦然
七、并发与线程(63-80)#
- 创建线程的三种方式:
Thread、Runnable、Callable(有返回值)
start() 启动线程,run() 只是普通方法调用
synchronized 可锁实例方法、静态方法(锁 Class)、代码块
wait() 释放锁,sleep() 不释放锁,yield() 让出 CPU 但不释放锁
wait()/notify() 必须在 synchronized 块中调用,否则抛 IllegalMonitorStateException
notify() 随机唤醒一个,notifyAll() 唤醒全部
- 死锁四条件:互斥、请求与保持、不可抢占、循环等待
- 破坏死锁:按固定顺序加锁、
tryLock() 超时、使用 ReentrantLock
volatile 保证可见性和有序性(禁止指令重排),不保证原子性
AtomicInteger 用 CAS 实现原子操作,incrementAndGet() 底层是 Unsafe.compareAndSwapInt
ThreadLocal 用完后必须 remove(),否则线程池复用导致内存泄漏
ThreadLocal 底层是 ThreadLocalMap,key 是弱引用,value 是强引用
ExecutorService 用 shutdown() 优雅关闭,shutdownNow() 立即关闭
- 线程池核心参数:核心线程数、最大线程数、存活时间、阻塞队列、拒绝策略
- 四种拒绝策略:
AbortPolicy(抛异常)、CallerRunsPolicy(调用者执行)、DiscardPolicy(丢弃)、DiscardOldestPolicy(丢弃最旧)
CachedThreadPool 最大线程数 Integer.MAX_VALUE,容易 OOM,慎用
FixedThreadPool 使用无界队列,任务积压可能导致 OOM
Future.get() 阻塞,CompletableFuture 异步回调更灵活
八、I/O 与 NIO(81-88)#
File 只是路径抽象,不表示真实文件,exists() 判断是否存在
FileInputStream 读取字节,FileReader 读取字符(默认编码可能乱码)
BufferedReader 用 readLine() 按行读取,Files.readAllLines() 更简洁
InputStreamReader 可指定字符集:new InputStreamReader(new FileInputStream("a.txt"), StandardCharsets.UTF_8)
try-with-resources 自动关闭多个资源,用分号分隔
Path/Paths/Files(Java 7+)替代 File,Files.walk() 遍历目录树
- NIO 核心:
Channel + Buffer + Selector(多路复用)
ByteBuffer 读写切换需调用 flip(),clear() 清空,compact() 压缩
九、JVM 与内存(89-95)#
- JVM 内存区域:堆、栈、方法区(元空间)、程序计数器、本地方法栈
- 堆分代:年轻代(Eden + S0 + S1)→ 老年代,默认比例 8:1:1
OutOfMemoryError 常见原因:堆 OOM、元空间 OOM、直接内存 OOM、栈溢出
- 栈溢出
StackOverflowError,递归过深或无终止条件
System.gc() 仅建议 GC,不保证执行
finalize() 已废弃(Java 9+),对象自救不靠谱
- 类加载器:Bootstrap(rt.jar)→ Extension → Application,双亲委派模型
十、日期与时间(96-100)#
java.util.Date 可变、线程不安全,已废弃,用 java.time.*(Java 8+)
LocalDate / LocalTime / LocalDateTime 不含时区,ZonedDateTime 含时区
Instant 时间戳(秒/纳秒),Duration 计算时间差,Period 计算日期差
- 格式化用
DateTimeFormatter 线程安全,替代 SimpleDateFormat(线程不安全)
LocalDateTime.now() 获取当前时间,parse("2026-07-09") 按 ISO 标准解析
十一、语法糖与常见坑(101-110)#
- 泛型编译期擦除,运行时无泛型信息(
List<String> 和 List<Integer> 在运行时相同)
- 可变参数本质是数组,
public void method(String... args) 可传数组或逗号分隔
- 枚举
enum 默认继承 Enum,不能被继承,构造器私有
- 匿名内部类持有外部类引用(
this$0),可能导致内存泄漏
- 接口默认方法
default,静态方法 static,接口中变量默认 public static final
- 抽象类可有构造器,接口无构造器
switch 支持 byte/short/char/int/String/enum,不支持 long/float/double
break 跳出循环,continue 跳过本次,return 结束方法
- 标签
label: 可跳出外层循环,但不推荐使用
- 数组协变:
String[] 是 Object[] 的子类,但集合泛型不变
十二、网络与反射(111-118)#
URL 和 URI 区别:URI 是标识符,URL 是定位符(包含协议)
HttpURLConnection 原生 HTTP 客户端,但 Apache HttpClient / OkHttp 更常用
Socket 阻塞 I/O,ServerSocket 监听端口,accept() 阻塞等待连接
- 反射
Class.forName() 初始化类,ClassLoader.loadClass() 不初始化
Method.invoke() 性能差,但反射能绕过私有访问(setAccessible(true))
Proxy.newProxyInstance() 动态代理只能代理接口,CGLIB 可代理类
- 注解保留策略:
SOURCE(源码)、CLASS(字节码)、RUNTIME(运行时)
- 序列化实现
Serializable 接口,serialVersionUID 用于版本兼容,不声明则自动生成
十三、设计原则与模式(119-123)#
- 单例双重检查需
volatile,防止指令重排导致半初始化对象被读取
- 工厂模式解耦,策略模式消除 if-else,观察者模式事件驱动
- 依赖倒置:依赖抽象而非具体实现
- 开闭原则:对扩展开放,对修改封闭
- 里氏替换:子类可以替换父类出现的地方
十四、Linux 与常用命令(124-128)#
nohup java -jar app.jar & 后台运行,输出到 nohup.out
jps 查看 Java 进程,jstack 打印线程堆栈,jmap 查看堆内存,jstat 监控 GC
kill -15 优雅关闭(SIGTERM),kill -9 强制杀死(SIGKILL)
tail -f app.log 实时查看日志,grep -C 10 "error" app.log 显示上下文
netstat -tlnp 查看端口占用,lsof -i:8080 查看指定端口
十五、数据库与 JDBC(129-133)#
PreparedStatement 防 SQL 注入,占位符 ?,编译一次执行多次
Statement 拼接字符串有注入风险,不用
ResultSet 游标从 1 开始,next() 移动指针,getString(1) 按索引取
- 事务隔离级别:读未提交、读已提交、可重复读、串行化
- 连接池用 HikariCP(默认)、Druid,不要手动创建连接
十六、Maven / Gradle(134-137)#
- Maven 生命周期:
clean → compile → test → package → install → deploy
provided 作用域表示运行时由容器提供(如 servlet-api)
- 依赖传递:
compile 传递,test 不传递,provided 不传递
- 版本冲突用
dependencyManagement 锁定版本,或用 exclude 排除
十七、工具与调试(138-142)#
System.out.println() 性能差,生产用日志框架(SLF4J + Logback)
- 日志级别:ERROR > WARN > INFO > DEBUG > TRACE
assert 默认禁用,需 -ea 开启,生产慎用
Objects.requireNonNull() 判空抛 NullPointerException,比手动 if 简洁
Optional 用来表示可能为 null 的返回值,不要用作字段或参数
十八、编码规范与常识(143-150)#
- 包名全小写,类名大驼峰,方法/变量小驼峰,常量全大写 + 下划线
- 方法名用动词(
getUser),变量名用名词(userName)
- 布尔变量用
is / has / can 开头(isDeleted)
- 一个
.java 文件只能有一个 public 类,文件名必须和 public 类名一致
- 构造器不能
static,不能被 final 修饰
static 块在类加载时执行一次,{} 实例块在构造器前执行
- 匿名对象(
new User())用完即抛,适合单次使用
- 永远不要在线上环境用
System.out 打印大对象,更不要用 e.printStackTrace()