Java 基础篇

本文以速查笔记的形式,简要梳理 Java 基础类型、集合、异常、反射、并发、网络与 JDK 8 常用特性。

一、基本类型与常用字符串类

1. 八种基本类型

  • 整数类型:byte(8 位)、short(16 位)、int(32 位)、long(64 位)。
  • 浮点类型:float(32 位)、double(64 位)。浮点数存在精度误差,精确金额计算通常使用 BigDecimal
  • 字符类型:char(16 位),表示一个 UTF-16 代码单元,不一定等于一个完整的 Unicode 字符。
  • 布尔类型:boolean,只有 truefalse;Java 语言规范没有规定其具体存储位数。

2. String、StringBuffer 与 StringBuilder

  • String 是引用类型,不是基本类型;对象不可变,适合表示不会频繁修改的字符串。
  • Java 只有值传递。传递对象时,传递的是“引用值的副本”,并不是引用传递。
  • StringBuffer 的主要方法使用 synchronized,线程安全但开销相对较高,默认容量为 16。
  • StringBuilder 非线程安全,单线程下性能更好,默认容量同样为 16。

3. 原子类与累加器

  • AtomicInteger 等原子类通过 CAS 实现无锁原子更新,例如 incrementAndGet()
  • LongAdder 在高并发下将竞争分散到多个 Cell,读取时汇总结果,吞吐量通常高于单一原子变量;并发更新期间的 sum() 不保证是严格瞬时快照。

二、异常体系

Java 异常体系的根类是 Throwable,主要分为 ErrorException

  • RuntimeException 及其子类属于非受检异常,常见的有 NullPointerExceptionIndexOutOfBoundsExceptionClassCastException
  • RuntimeException 之外的 Exception 通常属于受检异常,必须捕获或通过 throws 声明,例如 IOExceptionFileNotFoundExceptionSQLException
  • Error 通常表示 JVM 或系统层面的严重问题,应用程序一般难以恢复,例如 StackOverflowErrorOutOfMemoryError

try-with-resources 写法为 try (资源声明) { ... }。资源只要实现 AutoCloseable,离开代码块时就会自动关闭,常用于文件流、网络流和数据库连接。

三、集合框架

1. Map

  • HashMap:非线程安全。默认负载因子为 0.75,首次放入元素时通常初始化为容量 16,扩容一般为 2 倍。JDK 8 使用“数组 + 链表 + 红黑树”;桶内节点达到 8 且数组容量至少为 64 时才会树化。
  • 需要简单同步包装时可使用 Collections.synchronizedMap(),遍历时仍需在返回的 Map 上手动同步。
  • ConcurrentHashMap:线程安全。JDK 8 主要结合 CAS 与 synchronized 控制并发,读取操作大多不加锁。
  • TreeMap:基于红黑树,按键的自然顺序或指定 Comparator 排序,常用操作复杂度通常为 O(log n)。

2. List

  • ArrayList:动态数组,随机访问快、尾部追加高效,中间插入和删除可能移动元素;非线程安全。默认构造时为空,首次添加通常扩为 10,后续约按 1.5 倍扩容。
  • 需要同步包装时可使用 Collections.synchronizedList();遍历时同样需要手动同步。
  • CopyOnWriteArrayList:线程安全,写操作会复制底层数组,适合读多写少的场景。
  • LinkedList:双向链表,无固定容量;已定位节点后的插入、删除较快,但随机访问较慢,且非线程安全。
  • Vector:多数方法使用 synchronized,默认容量为 10;未指定容量增量时通常按 2 倍扩容。它属于较早期的线程安全容器。

四、反射与注解

  • 获取 ClassClass.forName("完整类名")类名.class对象.getClass()
  • 实例化对象:推荐通过 Constructor.newInstance()Class.newInstance() 已被弃用。
  • getDeclaredField/Method/Constructor 可获取当前类声明的成员,包括私有成员;不带 Declared 的方法主要获取公开成员,并会考虑继承关系。
  • 可通过 Method.invoke() 调用方法,通过 setAccessible(true) 尝试访问非公开成员;在模块化环境中仍可能受访问限制。
  • getAnnotation() 用于读取运行期可见的注解,注解需配置合适的 @Retention

五、代理与 Spring AOP

  • 静态代理:代理类通常由开发者提前编写,与目标类实现相同接口,结构直观,但扩展时容易增加代理类数量。
  • JDK 动态代理:基于接口,通过实现 InvocationHandler 在运行期生成代理对象。
  • CGLIB 动态代理:通过生成目标类的子类并修改字节码实现,不要求目标类实现接口,但无法代理 final 类或覆盖 final 方法。
  • Spring AOP 通常在目标实现接口时可使用 JDK 动态代理,没有接口时使用 CGLIB;也可通过配置强制使用 CGLIB。

六、IO 与 NIO

  • 传统 IO 面向流,常见调用是阻塞式的:数据未准备好或写入未完成时,线程可能等待。
  • NIO 主要面向 ChannelBuffer,支持选择器 Selector。可选择通道能够工作在非阻塞模式,但 NIO 并不代表所有 API 都天然非阻塞。
  • 阻塞 IO 编程简单,适合连接量较小的场景;NIO 更适合大量连接与事件驱动的网络程序。

七、常见设计模式

  • 单例模式:保证一个类在特定范围内只有一个实例,并提供统一访问入口;实现时需注意并发安全、序列化和反射问题。
  • 工厂模式:将对象创建过程集中管理,降低调用方与具体实现之间的耦合。常见形式包括简单工厂、工厂方法和抽象工厂。
  • 观察者模式:被观察对象状态变化时,通知多个订阅者,适合事件通知与发布订阅场景。

八、Socket 与网络基础

1. 网络分层

常见的 TCP/IP 四层模型为:应用层、传输层、网络层、网络接口层(链路层)。

2. TCP

  • TCP 面向连接、面向字节流,提供可靠、有序、全双工通信,适合文件传输、业务请求等重视可靠性的场景。
  • 三次握手:客户端发送 SYN,服务端返回 SYN + ACK,客户端再发送 ACK
  • 常见的四次挥手:主动方发送 FIN,被动方返回 ACK;被动方处理完剩余数据后发送 FIN,主动方返回 ACK

3. UDP

  • UDP 无连接、面向报文,不保证可靠性、顺序和重传,但协议开销小、时延低。
  • 支持单播、广播和多播,常用于实时音视频、在线游戏、DNS 等允许一定丢包或由应用层保证可靠性的场景。

九、多线程与线程池

1. 常见线程池

  • newCachedThreadPool:线程数可能快速增长,任务过多时存在耗尽系统资源的风险。
  • newFixedThreadPool:线程数固定,但使用无界队列,任务堆积时可能导致内存溢出。
  • newSingleThreadExecutor:单线程串行执行,也使用无界队列。
  • newScheduledThreadPool:支持延迟和周期任务,任务大量堆积时同样需要关注内存风险。

生产环境通常建议根据业务量显式创建 ThreadPoolExecutor,设置核心线程数、最大线程数、队列容量、线程工厂和拒绝策略。Guava 的 ThreadFactoryBuilder 可辅助设置线程名称,但不是 JDK 自带类。

2. 拒绝策略与异步结果

  • RejectedExecutionHandler 用于在线程池和队列都无法接收新任务时决定处理方式。JDK 内置抛异常、调用者执行、直接丢弃、丢弃最旧任务等策略。
  • Future.get() 会阻塞等待任务结果;可使用带超时的 get,或使用 CompletableFuture 组合异步任务。

3. synchronized 与 volatile

  • synchronized 提供互斥与可见性,可修饰实例方法、静态方法或代码块;实例锁和类锁作用对象不同。
  • volatile 保证变量的可见性,并通过内存屏障限制相关指令重排,但不保证复合操作的原子性,例如 count++ 仍不是原子操作。

十、JDK 8 常用特性

  • Lambda 表达式:简化函数式接口的实现,例如 (a, b) -> a + b
  • @FunctionalInterface:标记函数式接口。函数式接口只能有一个抽象方法,但可以包含默认方法、静态方法以及与 Object 公共方法相同的方法声明。
  • 方法引用:Lambda 的简写形式,常见写法有 类名::静态方法对象::实例方法类名::实例方法类名::new
  • Stream API:以声明式方式处理集合,常见中间操作有 filtermap,终止操作有 reducecollect。Stream 通常是惰性执行的,且不能重复消费。
  • 接口增强:接口可以定义 default 默认方法和 static 静态方法,便于在兼容已有实现类的前提下扩展接口能力。

总结

Java 基础学习应重点理解类型与内存语义、异常处理、集合底层结构、反射与代理、IO 模型、网络协议以及并发工具的适用边界。掌握“为什么这样设计”和“适合什么场景”,比单纯记忆默认参数更重要。