Java-基础
Java集合:
普通集合:
List(列表)
- 底层实现:ArrayList 和 LinkedList。
- ArrayList 基于动态数组,支持快速随机访问元素,但插入和删除操作(特别是中间位置的操作)较慢。
- LinkedList 基于双向链表,允许在任何位置进行快速的插入和删除操作,但随机访问速度较慢。
- 适用场景:当你需要一个可以容纳重复元素的有序集合,并且可能需要频繁地遍历或访问元素时使用。
Set(集)
- 底层实现:HashSet, LinkedHashSet 和 TreeSet。
- HashSet 使用哈希表实现,不保证元素的顺序,不允许重复元素,提供常数时间的基本操作(添加、移除、查询)。
- LinkedHashSet 维护了一个双向链表以保持元素的插入顺序,同时利用哈希表保证了性能。
- TreeSet 使用红黑树实现,能保持元素按自然顺序或者自定义顺序排序,不允许重复元素,但操作的时间复杂度为O(log n)。
- 适用场景:当你需要确保集合中没有重复元素,并且/或者希望按照特定顺序处理这些元素时使用。
Queue(队列)
- 底层实现:LinkedList, PriorityQueue 等。
- LinkedList 可以作为双端队列使用,支持在两端进行插入和移除操作。
- PriorityQueue 使用堆实现,队列头部是最小(或最大,取决于构造函数)的元素。
- 适用场景:当需要遵循“先进先出”(FIFO)原则或优先级队列(基于优先级处理元素)时使用。
Deque(双端队列)
- 底层实现:ArrayDeque 和 LinkedList。
- ArrayDeque 是基于循环数组实现的,允许在两端高效地添加和移除元素。
- LinkedList 同样可以用作双端队列。
- 适用场景:当你需要在一个序列的两端进行高效地插入和删除操作时使用。
Map(映射)
- 底层实现:HashMap, LinkedHashMap 和 TreeMap。
- HashMap 使用哈希表实现,键值对之间无序,查找、插入和删除操作平均时间为常数时间。
- LinkedHashMap 在HashMap的基础上增加了双向链表来维护元素的插入顺序或访问顺序。
- TreeMap 基于红黑树实现,键值对会按键的自然顺序或者自定义比较器排序,操作的时间复杂度为O(log n)。
- 适用场景:当你需要通过键来快速查找、插入、删除对应的值时使用。
线程安全集合:
ConcurrentHashMap
- 设计与实现:基于哈希表实现,但使用了分段锁(Segment)技术来减少锁的竞争。每个Segment都继承自ReentrantLock,可以独立加锁,从而允许多个线程同时访问不同的段。
- 线程安全策略:通过将数据分成多个段,使得不同段的数据可以被并发地修改和读取,极大地提高了并发性能。
CopyOnWriteArrayList 和 CopyOnWriteArraySet
- 设计与实现:写操作时进行复制整个底层数组,在副本上进行修改,完成后将引用指向新的数组。适用于读多写少的场景。
- 线程安全策略:写操作是通过创建底层数组的新副本来实现的,这避免了传统同步列表在写操作时需要锁定整个列表的问题,因此读操作可以在不锁定的情况下进行。
ConcurrentLinkedQueue 和 ConcurrentLinkedDeque
- 设计与实现:基于无锁算法实现的先进先出(FIFO)队列,使用CAS(Compare-And-Swap)操作保证线程安全。
- 线程安全策略:利用原子变量和非阻塞同步机制来确保线程安全性,特别适合于高并发环境下的队列操作。
BlockingQueue 接口及其实现类(如 LinkedBlockingQueue, ArrayBlockingQueue)
- 设计与实现:提供了一个线程安全的队列接口,其内部使用锁来保护状态,某些实现还提供了有界队列的支持。
- 线程安全策略:通过显式的锁和条件对象来控制对队列的访问,允许生产者等待队列不满以及消费者等待队列不空的状态。
SynchronousQueue
- 设计与实现:不存储元素的队列,每一个put操作必须等待一个take操作,反之亦然。
- 线程安全策略:直接在线程间传递数据,没有额外的缓冲区,确保了线程间的直接通信。
Collections.synchronizedXXX 方法包装的标准集合
- 例如
synchronizedList
,synchronizedMap
等,通过对标准集合的方法加上 synchronized 关键字来达到线程安全的目的。 - 线程安全策略:虽然简单易用,但由于所有的方法调用都需要获取同一个锁,所以在高并发情况下性能可能不如专门设计的并发集合。
- 例如
List使用注意事项:

IO模型:
BIO (Blocking I/O)
- 描述:BIO 是传统的阻塞式I/O模型,所有的socket连接都是基于一个线程对应一个请求的方式进行处理。当一个线程执行读或写操作时,如果数据未准备好(对于读操作)或者发送缓冲区已满(对于写操作),该线程将会被阻塞,直到操作完成。【连接数少且固定】
特点:
- 编程模型简单,易于理解和使用。
- 线程资源消耗大,每个连接都需要一个独立的线程来处理,不适合高并发场景。
NIO (New I/O 或 Non-blocking I/O)
- 描述:NIO 引入了通道(Channel)和缓冲区(Buffer)的概念,并提供了非阻塞I/O的支持。通过选择器(Selector),可以管理多个通道,这样单个线程就可以处理多个网络连接。【高并发网络】
特点:
- 支持非阻塞模式,允许线程在等待I/O操作完成的同时执行其他任务,提高了线程的利用率。
- 使用更少的线程处理更多的连接,非常适合高并发场景。
- 需要开发者自行管理复杂的逻辑,如注册、选择、取消等操作。
AIO (Asynchronous I/O)
- 描述:AIO 是异步非阻塞的I/O模型,它进一步扩展了NIO的功能,提供了真正的异步I/O支持。应用程序可以通过回调机制,在I/O操作完成后得到通知。【异步IO,回调函数】
特点:
- 最高级别的抽象,提供最简单的编程模型,因为所有的I/O操作都是由操作系统负责完成,并在完成后通知应用程序。
- 相比于NIO,减少了开发者的负担,因为不需要直接管理多路复用的选择器。
- 在某些情况下可能不如NIO性能优越,因为它的实现依赖于操作系统的支持情况。
抽象类和接口:
- 定义和设计:抽象类是使用abstract关键字定义的类,可以包含抽象方法和非抽象方法,可以有实例变量和构造方法;接口通过interface关键字定义,只能包含抽象方法、默认方法和静态方法,不包含实例变量或构造方法。
- 继承关系:一个类只能继承自一个抽象类,但可以实现多个接口。继承抽象类体现的是"is-a"关系,而实现接口体现的是"can-do"关系。
- 构造方法:抽象类可以有构造方法,子类可以通过super()调用父类的构造方法;接口没有构造方法。
- 默认实现:抽象类可以包含非抽象方法,子类可以直接使用;接口可以包含默认方法,提供通用实现,子类可以选择重写或者使用默认实现。
- 设计目的:抽象类的设计目的是提供类的继承机制,实现代码复用,适用于拥有相似行为和属性的类;接口的设计目的是定义一组规范或契约,实现类遵循特定的行为和功能,适用于不同类之间的解耦和多态性实现。
设计模式:
创造者模式:
单例模式 (Singleton Pattern)
- 思路:确保一个类只有一个实例,并提供一个全局访问点。
- 应用场景:当系统只需要一个实例对象来协调动作时非常有用,比如日志记录、数据库连接等。
工厂方法模式 (Factory Method Pattern)
- 思路:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。这样,工厂方法将实例化推迟到子类。
- 应用场景:当一个类无法预料要创建哪种类的对象或希望由其子类来指定所要创建的对象时使用。
抽象工厂模式 (Abstract Factory Pattern)
- 思路:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 应用场景:当你需要为一个产品族提供一致的创建接口而不指定具体类时适用,例如GUI工具包在不同平台上的实现。
建造者模式 (Builder Pattern)
- 思路:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
- 应用场景:当构造函数参数过多且很多参数都是可选的情况下,使用建造者模式可以让代码更清晰易读。
结构型设计模式:
适配器模式 (Adapter Pattern)
- 思路:允许将不兼容的接口转换为可兼容的形式,使得原本由于接口不匹配而不能一起工作的类可以一起工作。
- 应用场景:当你想要使用一些已经存在的类,但是它们的接口并不符合你的需求时,可以使用适配器模式。
桥接模式 (Bridge Pattern)
- 思路:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
- 应用场景:当一个类希望其子类能够选择不同的实现方式时,或者当需要在运行时动态选择实现时使用桥接模式。
组合模式 (Composite Pattern)
- 思路:允许你将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端可以统一地对待单个对象和对象组合。
- 应用场景:适用于那些需要处理简单元素和复杂结构相同的方式的场景,例如文件系统的目录结构管理。
装饰器模式 (Decorator Pattern)
- 思路:动态地给一个对象添加一些额外的职责。就扩展功能而言,装饰器模式相比生成子类更加灵活。
- 应用场景:当你需要在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责时使用。
享元模式 (Flyweight Pattern)
- 思路:通过共享技术来实现相同或相似对象的支持,以减少内存占用和提高性能。
- 应用场景:当一个应用程序使用大量的对象,而这些对象造成了很大的存储开销时;或者对象的大多数状态都可以外部化时适用。
代理模式 (Proxy Pattern)
- 思路:为其它对象提供一种代理以控制对这个对象的访问。
- 应用场景:远程代理(代表远程的对象)、虚拟代理(根据需要创建开销很大的对象)、保护代理(基于权限控制对资源的访问)等。
行为型模式:
策略模式 (Strategy Pattern)
- 思路:定义一系列算法,将每个算法封装起来,并使它们可以互换使用。
- 应用场景:当存在多个算法家族且希望在运行时根据需要选择不同的算法族或算法变体时非常有用。
模板方法模式 (Template Method Pattern)
- 思路:定义一个操作中的算法骨架,而将一些步骤延迟到子类中去实现。模板方法使得子类可以在不改变算法结构的前提下重新定义算法的某些步骤。
- 应用场景:当你有一个基础算法,但其中某些步骤的具体实现可能因情况而异时使用。
观察者模式 (Observer Pattern)
- 思路:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。
- 应用场景:适用于当一个对象的状态变化需要通知其他对象,而不需要这些对象紧密耦合的情况。
迭代器模式 (Iterator Pattern)
- 思路:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
- 应用场景:用于遍历集合对象,无需了解其底层结构(如数组、链表等),为不同的数据结构提供统一的遍历接口。
责任链模式 (Chain of Responsibility Pattern)
- 思路:避免请求发送者与接收者耦合在一起,让多个对象都有机会处理请求,将这些对象连接成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
- 应用场景:适用于有多个对象可以处理同一请求,具体由哪个对象处理取决于运行时刻条件或优先级顺序。
命令模式 (Command Pattern)
- 思路:将请求封装为对象,从而使你可以用不同的请求对客户进行参数化;对请求排队或记录日志,以及支持可撤销的操作。
- 应用场景:适合于需要执行远程调用、日志记录、事务管理等情况下的命令封装和调度。