一、集合体系
集合一共分为两部分:Collection(单列集合)每个元素(数据)只包含一个值。
Map(双列集合)每个元素包含两个值(键值对)。
二、ArrayList和LinkedList的区别
数据结构:ArrayList基于动态数组实现,LinkedList基于双向链表实现。
随机访问:ArrayList支持快速随机访问,时间复杂度为O(1);LinkedList随机访问效率低,时间复杂度为O(n)。
插入和删除:在中间位置插入和删除元素时,ArrayList需要移动大量元素,时间复杂度为O(n);LinkedList只需修改指针,时间复杂度为O(1)。
内存占用:ArrayList内存占用相对紧凑;LinkedList每个节点都需要额外的指针空间,内存占用较多。
三、让ArrayList变得线程安全
使用Collections.synchronizedList()
方法,将ArrayList转换为线程安全的列表。
使用CopyOnWriteArrayList
,它在修改操作时会创建一个新的底层数组,读操作不会被写操作阻塞。
四、HashMap的底层结构
JDK 1.8之前,HashMap底层由数组和链表组成。JDK 1.8及之后,当链表长度超过阈值(默认为8)时,链表会转换为红黑树,以提高查找效率。
底层数组的长度为16
长度是2的幂次方:计算高效:在计算元素存储位置时,使用位运算(n - 1) & hash
代替取模运算,提高计算效率。分布均匀:能使元素在数组中的分布更均匀,减少哈希冲突,提高查询性能。
五、线程安全的集合
-
Vector
:通过在方法上添加synchronized
关键字实现线程安全,所有对Vector
的操作都是同步的。 -
Hashtable
:与Vector
类似,方法基本都被synchronized
修饰。 -
ConcurrentHashMap
:JDK 1.7使用分段锁,JDK 1.8使用CAS和synchronized
。 -
CopyOnWriteArrayList
:写操作时复制数组,读操作无锁,读写分离。
六、快速失败机制
当多个线程对集合进行并发修改时,可能会抛出ConcurrentModificationException
异常。Java集合在遍历过程中,通过记录集合的修改次数modCount
,当遍历过程中发现modCount
发生变化,就认为集合被其他线程修改了,从而抛出异常。
七、红黑树红黑规则
-
每一个节点或是红色的,或者是黑色的
-
根节点必须是黑色
-
如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
-
如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)
-
对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
八、红黑树与B+树的区别
节点存储数据:B+树的非叶子节点只存储键,叶子节点存储键和数据;红黑树的每个节点都存储键和数据。
查询效率:B+树的查询效率更稳定,所有数据都在叶子节点,查询时间复杂度为O(log n);红黑树查询时间复杂度也是O(log n),但可能需要遍历更多节点。
应用场景:B+树常用于数据库索引等需要大量数据存储和高效范围查询的场景;红黑树常用于Java集合等需要快速插入、删除和查找的场景。
九、Stream流中的方法
Stream流中间操作方法
方法名 | 说明 |
---|---|
Stream<T> filter(Predicate predicate) | 用于对流中的数据进行过滤 |
Stream<T> limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream<T> skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
Stream<T> distinct() | 返回由该流的不同元素(根据Object.equals(Object) )组成 |
Stream流的终结方法
方法名 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行操作 |
long count() | 返回此流中的元素数 |
收集方法
方法名 | 说明 |
---|---|
R collect(Collector collector) | 把结果收集到集合中 |
十、反射
获取Class类对象的三种方式:
类名.class属性
对象名.getClass()方法
Class.forName(全类名)方法
应用场景:
框架开发:Spring框架中通过反射实现依赖注入和AOP等功能。
动态代理:在Java中,可通过反射创建动态代理类,为目标对象生成代理对象。
对象的动态创建和操作:根据配置文件或用户输入动态创建对象。