#33
写算法题 黑马的视频争取简单的过一遍 要考试啦密码的
写底层代码 秘密的 底层代码有点长啊 看不懂 难 找了几个视频课 看看吧
想看中文版jdk api吧
算了慢慢看 先把几个顶级父类给看会了 object system string stringbuilder
算法
单路递归
package com.itheima.Recursion; public class singleRecursion { public static void main(String[] args) { } //E01 阶乘 private static int f(int n){ if (n==1){ return 1; }return n * f(n -1); } // E02 反转打印 public static void reversePrint(String str,int index ){ if (index == str.length()){ return; } reversePrint(str,index+1); System.out.print(str.charAt(index)); } //E03 二分查找 public static int binarySearch(int []a,int target){ return recursion(a,target,0,a.length-1); } private static int recursion(int[] a, int target, int i, int j) { if(i > j){ return -1; } int m = (i+j)>>>1; if(target < a[m]){ return recursion(a,target,i,m-1); } else if (a[m] < target) { return recursion(a,target,m+1,j); }else{ return m; } } //E4 冒泡排序 private static void bubble(int[]a ,int low, int high){ if(low == high){ return; } int j = low; for (int i = low; i < high; i++) { if (a[i] > a[i+1]){ swap(a,i,i+1); j=i; } bubble(a,low,j); } } private static void swap(int[] a,int i,int j){ int temp = a[i]; a[i] = a[j]; a[j] = temp; } //E5 插入排序 public static void insertSort(int [] a,int low,int high){ if (low > high){ return; } int i = low -1; int t = a[low]; while(i>=0 && a[i]>t){ a[i+1] = a[i]; i--; } if (i + 1 != low){ a[i+1] = t; } insertSort(a,low,i+1); } //E6 约瑟夫问题 }
注释版
package com.itheima.Recursion; /** * 递归算法实现类,包含多种常见递归算法的实现 * <p> * 递归算法的核心思想是将问题分解为规模更小的同类子问题, * 通过解决子问题来最终解决原问题 */ public class singleRecursion { public static void main(String[] args) { // 测试代码可在此处添加 } /** * 计算整数n的阶乘(n!) * <p> * 阶乘定义:n! = n × (n-1) × (n-2) × ... × 1 * 递归公式:f(n) = n × f(n-1),其中f(1) = 1 * * @param n 要计算阶乘的整数,要求n ≥ 1 * @return n的阶乘值 * @throws IllegalArgumentException 当n < 1时抛出异常 */ private static int f(int n) { if (n < 1) { throw new IllegalArgumentException("n必须为正整数,当前n = " + n); } if (n == 1) { return 1; // 递归终止条件:1的阶乘为1 } return n * f(n - 1); // 递归调用:n! = n × (n-1)! } /** * 递归实现字符串的反转打印 * <p> * 例如:输入"abc",输出"cba" * 递归逻辑:先递归处理index+1位置到字符串末尾,再打印当前index位置的字符 * * @param str 要反转打印的字符串 * @param index 当前处理的字符索引,初始调用时传0 */ public static void reversePrint(String str, int index) { if (str == null) { throw new NullPointerException("字符串不能为null"); } if (index == str.length()) { return; // 递归终止条件:已处理完所有字符 } reversePrint(str, index + 1); // 先递归处理下一个字符 System.out.print(str.charAt(index)); // 再打印当前字符,实现反转效果 } /** * 二分查找算法的递归实现 * <p> * 在有序数组中查找目标值的索引 * 时间复杂度:O(log n),空间复杂度:O(log n)(递归栈) * * @param a 有序整数数组 * @param target 要查找的目标值 * @return 目标值在数组中的索引,若不存在则返回-1 * @throws NullPointerException 当数组为null时抛出异常 */ public static int binarySearch(int[] a, int target) { if (a == null) { throw new NullPointerException("数组不能为null"); } return recursion(a, target, 0, a.length - 1); } /** * 二分查找的递归辅助方法 * * @param a 有序整数数组 * @param target 要查找的目标值 * @param i 查找区间的起始索引(包含) * @param j 查找区间的结束索引(包含) * @return 目标值在数组中的索引,若不存在则返回-1 */ private static int recursion(int[] a, int target, int i, int j) { if (i > j) { return -1; // 递归终止条件:查找区间为空,目标值不存在 } int m = (i + j) >>> 1; // 计算中间索引,使用无符号右移避免整数溢出 if (target < a[m]) { return recursion(a, target, i, m - 1); // 目标值在左半区间 } else if (a[m] < target) { return recursion(a, target, m + 1, j); // 目标值在右半区间 } else { return m; // 找到目标值,返回索引 } } /** * 递归实现冒泡排序算法 * <p> * 冒泡排序思想:通过相邻元素的比较和交换,将较大的元素逐步"冒泡"到数组末尾 * 递归版本:每次排序将当前区间的最大元素放到正确位置,然后递归处理剩余区间 * * @param a 要排序的整数数组 * @param low 排序区间的起始索引(包含) * @param high 排序区间的结束索引(包含) * @throws NullPointerException 当数组为null时抛出异常 */ private static void bubble(int[] a, int low, int high) { if (a == null) { throw new NullPointerException("数组不能为null"); } if (low == high) { return; // 递归终止条件:区间只有一个元素,已排序 } int j = low; for (int i = low; i < high; i++) { if (a[i] > a[i + 1]) { swap(a, i, i + 1); // 交换相邻的逆序元素 j = i; // 记录最后一次交换的位置 } } bubble(a, low, j); // 递归处理剩余未排序区间 } /** * 交换数组中两个位置的元素 * * @param a 整数数组 * @param i 要交换的第一个位置 * @param j 要交换的第二个位置 */ private static void swap(int[] a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } /** * 递归实现插入排序算法 * <p> * 插入排序思想:将未排序元素插入到已排序部分的正确位置 * 递归版本:将当前元素插入到前low~high-1已排序区间的正确位置,然后递归处理下一个元素 * * @param a 要排序的整数数组 * @param low 当前处理的元素索引 * @param high 数组的最大索引(用于边界检查) * @throws NullPointerException 当数组为null时抛出异常 */ public static void insertSort(int[] a, int low, int high) { if (a == null) { throw new NullPointerException("数组不能为null"); } if (low > high) { return; // 递归终止条件:已处理完所有元素 } int i = low - 1; int t = a[low]; // 暂存当前要插入的元素 // 在已排序区间中找到插入位置 while (i >= 0 && a[i] > t) { a[i + 1] = a[i]; // 元素后移 i--; } if (i + 1 != low) { a[i + 1] = t; // 插入元素到正确位置 } insertSort(a, low + 1, high); // 递归处理下一个元素 } /** * 约瑟夫问题(待实现) * <p> * 约瑟夫问题描述:n个人围成一圈,从第1个人开始报数,报到m的人退出, * 然后从下一个人继续报数,直到所有人退出,求退出顺序 * <p> * 提示:可使用递归或循环实现,当前方法仅作为占位符 */ // E6 约瑟夫问题 // 实现思路:定义递归函数f(n, m)表示n个人报数,每次数到m的人退出,返回最后剩下的人的编号 // 递归公式:f(1, m) = 0; f(n, m) = (f(n-1, m) + m) % n; // 注意:编号从0开始 public static int josephusProblem(int n, int m) { if (n < 1 || m < 1) { throw new IllegalArgumentException("n和m必须为正整数"); } return josephus(n, m); } private static int josephus(int n, int m) { if (n == 1) { return 0; // 递归终止条件:只剩1个人,编号为0 } return (josephus(n - 1, m) + m) % n; // 递归公式 } }
多路递归
package com.itheima.Recursion; import java.util.LinkedList; public class multiRecursion { public static void main(String[] args) { } // E1 斐波那契数列 public static int f(int n){ if(n==0){ return 0; } if(n==1){ return 1; } return f(n-1)+f(n-2); } // E2汉诺塔问题? static void h(int n, LinkedList<Integer> a, LinkedList<Integer> b, LinkedList<Integer> c){ if(n==0){ return; }else{ h(n-1,a,c,b); c.addLast(a.removeLast()); System.out.println(a+" "+b+" "+c); h(n-1,b,a,c); } } //E03 杨辉三角 public static void print(int n){ for(int i=0;i<n;i++){ if(i<n-1){ System.out.printf("%"+(n-1-i)*2+"s"," "); } for(int j = 0; j<i+1;j++){ System.out.printf("%-4d",element(i,j)); } System.out.println(); } } public static int element(int i, int j){ if(i==0 || j==i){ return 1; } return element(i-1,j-1)+element(i-1,j); } }
注释版
package com.itheima.Recursion; import java.util.LinkedList; /** * 多分支递归算法实现类,包含多种典型多递归分支问题的解决方案 * <p> * 多分支递归的特点是在递归过程中会产生多个子问题, * 每个子问题都需要独立求解,常见于分治思想的应用场景 */ public class multiRecursion { public static void main(String[] args) { // 测试代码可在此处添加 // 例如:System.out.println(f(10)); // 输出斐波那契数列第10项 // h(3, new LinkedList<>(), new LinkedList<>(), new LinkedList<>()); // 演示3层汉诺塔 // print(10); // 打印10层杨辉三角 } /** * 计算斐波那契数列的第n项 * <p> * 斐波那契数列定义:F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2) (n≥2) * 递归特点:每个问题分解为两个子问题,时间复杂度O(2^n),存在大量重复计算 * * @param n 项数(从0开始),要求n ≥ 0 * @return 斐波那契数列第n项的值 * @throws IllegalArgumentException 当n < 0时抛出异常 */ public static int f(int n) { if (n < 0) { throw new IllegalArgumentException("n必须为非负整数,当前n = " + n); } if (n == 0) { return 0; // 递归终止条件1:第0项为0 } if (n == 1) { return 1; // 递归终止条件2:第1项为1 } return f(n - 1) + f(n - 2); // 递归公式:F(n) = F(n-1) + F(n-2) } /** * 汉诺塔问题的递归解决方案 * <p> * 问题描述:有3根柱子A、B、C,A柱上有n个直径不同的圆盘(下大上小), * 要求将所有圆盘从A柱移动到C柱,每次只能移动一个圆盘, * 且小圆盘必须位于大圆盘之上 * <p> * 递归思路: * 1. 将n-1个圆盘从A柱经C柱移动到B柱 * 2. 将第n个圆盘从A柱移动到C柱 * 3. 将n-1个圆盘从B柱经A柱移动到C柱 * * @param n 要移动的圆盘数量 * @param a 起始柱(源柱) * @param b 中间柱(辅助柱) * @param c 目标柱(目的柱) * @throws NullPointerException 当柱子为null时抛出异常 */ static void h(int n, LinkedList<Integer> a, LinkedList<Integer> b, LinkedList<Integer> c) { if (a == null || b == null || c == null) { throw new NullPointerException("柱子不能为null"); } if (n == 0) { return; // 递归终止条件:没有圆盘需要移动 } else { // 步骤1:将n-1个圆盘从A柱经C柱移动到B柱 h(n - 1, a, c, b); // 步骤2:将第n个圆盘从A柱移动到C柱 c.addLast(a.removeLast()); // 打印当前状态(柱子上的圆盘) System.out.println(a + " " + b + " " + c); // 步骤3:将n-1个圆盘从B柱经A柱移动到C柱 h(n - 1, b, a, c); } } /** * 打印n层杨辉三角 * <p> * 杨辉三角特点: * 1. 每行数字左右对称,由1开始逐渐增大 * 2. 第n行(i从0开始)有n+1个元素 * 3. 每个元素等于上一行两肩元素之和:element(i,j) = element(i-1,j-1) + element(i-1,j) * * @param n 要打印的层数(n ≥ 1) * @throws IllegalArgumentException 当n < 1时抛出异常 */ public static void print(int n) { if (n < 1) { throw new IllegalArgumentException("层数必须≥1,当前n = " + n); } for (int i = 0; i < n; i++) { // 打印左侧空格,实现三角形对齐 if (i < n - 1) { System.out.printf("%" + (n - 1 - i) * 2 + "s", " "); } // 打印第i行的所有元素 for (int j = 0; j < i + 1; j++) { System.out.printf("%-4d", element(i, j)); } System.out.println(); // 换行 } } /** * 计算杨辉三角中第i行第j列的元素值(i,j从0开始) * <p> * 递归公式: * element(i,j) = 1 (当i=0或j=i时,即每行第一个和最后一个元素) * element(i,j) = element(i-1,j-1) + element(i-1,j) (其他情况) * * @param i 行索引(从0开始) * @param j 列索引(从0开始,且j ≤ i) * @return 杨辉三角中(i,j)位置的元素值 * @throws IllegalArgumentException 当j > i时抛出异常 */ public static int element(int i, int j) { if (j < 0 || j > i) { throw new IllegalArgumentException("列索引j必须满足0 ≤ j ≤ i,当前i=" + i + ", j=" + j); } if (i == 0 || j == i) { return 1; // 递归终止条件:每行第一个和最后一个元素为1 } // 递归计算:当前元素等于上一行两肩元素之和 return element(i - 1, j - 1) + element(i - 1, j); } }
队列
queue
package com.itheima.Queue; import java.util.Iterator; /** * 自定义队列接口,定义了队列的基本操作规范 * 遵循FIFO(先进先出)原则,元素从队尾入队,从队首出队 * * @param <E> 队列中元素的类型 */ public interface Queue<E> { /** * 将指定元素添加到队列尾部 * * @param o 要添加的元素 * @return 添加成功返回true;若队列已满,根据具体实现可能返回false或抛出异常 * @throws NullPointerException 如果指定元素为null(根据实现可能抛出) * @throws IllegalStateException 如果队列已满且实现不允许添加 */ boolean offer(E o); /** * 移除并返回队列的头部元素 * * @return 队列的头部元素;若队列为空,返回null */ E poll(); /** * 返回但不移除队列的头部元素 * * @return 队列的头部元素;若队列为空,返回null */ E peek(); /** * 判断队列是否为空 * * @return 如果队列为空,返回true;否则返回false */ boolean isEmpty(); /** * 判断队列是否已满 * * @return 如果队列已满,返回true;否则返回false */ boolean isFull(); /** * 返回一个用于遍历队列中元素的迭代器 * 迭代顺序:从队首到队尾 * * @return 一个迭代器实例 */ Iterator<E> iterator(); }
链表实现队列
package com.itheima.Queue; import java.util.Iterator; /** * 基于链表实现的队列,遵循FIFO(先进先出)原则 * 使用虚拟头节点简化边界处理,队首元素位于head.next * 队尾指针tail始终指向最后一个元素,支持容量限制 * * @param <E> 队列中元素的类型 */ public class LinkedListQueue<E> implements Queue<E> { /** * 链表节点类,存储元素数据和指向下一节点的引用 */ private static class Node<E> { E data; // 节点存储的数据 Node<E> next; // 指向下一个节点的引用 public Node(E data, Node<E> next) { this.data = data; this.next = next; } } private Node<E> head = new Node<>(null, null); // 虚拟头节点 private Node<E> tail = head; // 尾指针,初始指向头节点 private int size = 0; // 当前队列元素数量 private int capacity = Integer.MAX_VALUE; // 队列容量上限 // 初始化循环链表(空队列时tail指向head) { tail.next = head; } /** * 构造一个无容量限制的空队列 */ public LinkedListQueue() { } /** * 构造一个具有指定容量限制的空队列 * * @param capacity 队列的最大容量 * @throws IllegalArgumentException 如果指定容量小于等于0 */ public LinkedListQueue(int capacity) { if (capacity <= 0) { throw new IllegalArgumentException("容量必须大于0"); } this.capacity = capacity; } /** * 将元素添加到队列尾部 * * @param value 要添加的元素 * @return 添加成功返回true;若队列已满返回false * @throws NullPointerException 如果传入的元素为null */ @Override public boolean offer(E value) { if (value == null) { throw new NullPointerException("不允许添加null元素"); } if (isFull()) { return false; } else { // 创建新节点,next指向head形成循环 Node<E> node = new Node<>(value, head); tail.next = node; // 尾节点指向新节点 tail = node; // 更新尾指针 size++; return true; } } /** * 移除并返回队列的头部元素 * * @return 队列的头部元素;若队列为空返回null */ @Override public E poll() { if (isEmpty()) { return null; } else { Node<E> first = head.next; // 获取头节点的下一个节点(真正的队首) head.next = first.next; // 头节点指向原队首的下一个节点 if (first == tail) { // 如果移除的是最后一个元素 tail = head; // 尾指针重置为头节点 } size--; return first.data; } } /** * 返回但不移除队列的头部元素 * * @return 队列的头部元素;若队列为空返回null */ @Override public E peek() { if (isEmpty()) { return null; } else { return head.next.data; // 返回头节点的下一个节点的数据 } } /** * 判断队列是否为空 * * @return 若队列为空返回true,否则返回false */ @Override public boolean isEmpty() { return head == tail; // 当尾指针等于头节点时队列为空 } /** * 判断队列是否已满 * * @return 若队列达到容量上限返回true,否则返回false */ @Override public boolean isFull() { return size == capacity; // 元素数量达到容量时为满 } /** * 返回一个用于遍历队列元素的迭代器 * 迭代顺序:从队首到队尾 * * @return 迭代器实例 */ @Override public Iterator<E> iterator() { return new Iterator<E>() { Node<E> p = head.next; // 从队首开始迭代 @Override public boolean hasNext() { return p != head; // 当指针不等于头节点时还有元素 } @Override public E next() { E value = p.data; // 获取当前节点数据 p = p.next; // 指针后移 return value; } }; } }
数组实现队列
package com.itheima.Queue; import java.util.Iterator; /** * 基于数组实现的循环队列,遵循FIFO(先进先出)原则 * 使用头尾指针实现元素的高效入队和出队操作 * 数组容量比用户指定容量大1,用于区分队列空和满的状态 * * @param <E> 队列中元素的类型 */ public class ArrayQueue<E> implements Queue<E>, Iterable<E> { private int head = 0; // 队首指针,指向队列第一个元素 private int tail = 0; // 队尾指针,指向队列最后一个元素的下一个位置 private final E[] array; // 存储队列元素的数组 private final int length; // 数组的实际长度(比用户指定容量大1) /** * 构造一个具有指定容量的空队列 * * @param capacity 用户期望的队列容量 * @throws IllegalArgumentException 如果指定容量小于等于0 */ @SuppressWarnings("all") public ArrayQueue(int capacity) { if (capacity <= 0) { throw new IllegalArgumentException("容量必须大于0"); } this.length = capacity + 1; // 实际数组长度比用户指定容量大1 this.array = (E[]) new Object[length]; // 创建泛型数组 } /** * 将元素添加到队列尾部 * * @param o 要添加的元素 * @return 添加成功返回true;若队列已满返回false * @throws NullPointerException 如果传入的元素为null */ @Override public boolean offer(E o) { if (o == null) { throw new NullPointerException("不允许添加null元素"); } if (isFull()) { return false; } array[tail] = o; // 将元素放入队尾位置 tail = (tail + 1) % length; // 队尾指针循环后移 return true; } /** * 移除并返回队列的头部元素 * * @return 队列的头部元素;若队列为空返回null */ @Override public E poll() { if (isEmpty()) { return null; } else { E value = array[head]; // 获取队首元素 head = (head + 1) % length; // 队首指针循环后移 return value; } } /** * 返回但不移除队列的头部元素 * * @return 队列的头部元素;若队列为空返回null */ @Override public E peek() { if (isEmpty()) { return null; } else { return array[head]; // 返回队首元素 } } /** * 判断队列是否为空 * * @return 若队列为空返回true,否则返回false */ @Override public boolean isEmpty() { return tail == head; // 头尾指针相等时队列为空 } /** * 判断队列是否已满 * * @return 若队列已满返回true,否则返回false */ @Override public boolean isFull() { return (tail + 1) % length == head; // 尾指针的下一个位置是头指针时队列满 } /** * 返回一个用于遍历队列元素的迭代器 * 迭代顺序:从队首到队尾 * * @return 迭代器实例 */ @Override public Iterator<E> iterator() { return new Iterator<E>() { int p = head; // 从队首开始迭代 @Override public boolean hasNext() { return p != tail; // 当前位置不等于尾指针时还有元素 } @Override public E next() { E value = array[p]; // 获取当前位置元素 p = (p + 1) % length; // 指针循环后移 return value; } }; } }
题
package com.itheima.Queue; import java.util.ArrayList; import java.util.List; public class Queue_E { public static void main(String[] args) { // 示例用法 TreeNode root = new TreeNode(3); root.left = new TreeNode(9); root.right = new TreeNode(20); root.right.left = new TreeNode(15); root.right.right = new TreeNode(7); Solution solution = new Solution(); List<List<Integer>> result = solution.levelOrder(root); System.out.println(result); // 输出: [[3], [9, 20], [15, 7]] } /** * E01 二叉树层序遍历 * 使用队列实现按层遍历二叉树,每层元素存储在独立的列表中 */ static class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> result = new ArrayList<>(); if (root == null) { return result; } // 使用自定义链表队列存储待处理的节点 LinkedListQueue<TreeNode> queue = new LinkedListQueue<>(); queue.offer(root); int currentLevelCount = 1; // 当前层的节点数 while (!queue.isEmpty()) { int nextLevelCount = 0; // 下一层的节点数 List<Integer> currentLevel = new ArrayList<>(); // 处理当前层的所有节点 for (int i = 0; i < currentLevelCount; i++) { TreeNode node = queue.poll(); currentLevel.add(node.val); // 将下一层的子节点加入队列 if (node.left != null) { queue.offer(node.left); nextLevelCount++; } if (node.right != null) { queue.offer(node.right); nextLevelCount++; } } // 更新当前层节点数为下一层的节点数 currentLevelCount = nextLevelCount; result.add(currentLevel); } return result; } } /** * 二叉树节点定义 */ static class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } /** * 自定义链表队列实现 * @param <E> 队列元素类型 */ static class LinkedListQueue<E> { private static class Node<E> { E value; Node<E> next; public Node(E value, Node<E> next) { this.value = value; this.next = next; } } private final Node<E> head = new Node<>(null, null); // 虚拟头节点 private Node<E> tail = head; // 尾指针 private int size = 0; // 当前队列大小 private int capacity = 10000; // 默认容量限制 // 初始化循环链表 { head.next = head; } public LinkedListQueue() { } public LinkedListQueue(int capacity) { this.capacity = capacity; } /** * 向队列尾部添加元素 * @param value 待添加的元素 * @return 添加成功返回true,队列已满返回false */ public boolean offer(E value) { if (isFull()) { return false; } // 创建新节点并添加到队尾 Node<E> newNode = new Node<>(value, head); tail.next = newNode; tail = newNode; size++; return true; } /** * 移除并返回队列头部元素 * @return 队列头部元素,队列为空时返回null */ public E poll() { if (isEmpty()) { return null; } // 获取头节点的下一个节点(真正的队首元素) Node<E> first = head.next; head.next = first.next; // 如果移除的是最后一个元素,重置尾指针 if (first == tail) { tail = head; } size--; return first.value; } /** * 返回队列头部元素但不移除 * @return 队列头部元素,队列为空时返回null */ public E peek() { if (isEmpty()) { return null; } return head.next.value; } /** * 判断队列是否为空 * @return 队列为空返回true,否则返回false */ public boolean isEmpty() { return head == tail; } /** * 判断队列是否已满 * @return 队列已满返回true,否则返回false */ public boolean isFull() { return size == capacity; } } } // 622. 设计循环队列 class ExLeetcode622{ private static class Node{ int value; Node next; Node(int value, Node next) { this.value = value; this.next = next; } private final Node head = new Node(-1, null); private Node tail = head; private int size = 0; private int capacity = 0; { head.next = head; } private void ExLeetcode622(int capacity) { this.capacity = capacity; } public boolean enQueue(int value) { if (isFull()) { return false; } Node added = new Node(value, head); tail.next = added; tail = added; size += 1; return true; } public boolean deQueue() { if (isEmpty()) { return false; } Node first = head.next; head.next = first.next; if (first == tail) { tail = first; } size--; return true; } public int Front() { if (isEmpty()) { return -1; } return head.next.value; } public int Rear() { if (isEmpty()) { return -1; } return head.next.value; } public boolean isEmpty() { return size == 0; } public boolean isFull() { return size == capacity; } } }
栈
interface
public interface Stack<E> { /** * 向栈顶压入元素 * @param value 待压入值 * @return 压入成功返回 true, 否则返回 false */ boolean push(E value); /** * 从栈顶弹出元素 * @return 栈非空返回栈顶元素, 栈为空返回 null */ E pop(); /** * 返回栈顶元素, 不弹出 * @return 栈非空返回栈顶元素, 栈为空返回 null */ E peek(); /** * 判断栈是否为空 * @return 空返回 true, 否则返回 false */ boolean isEmpty(); /** * 判断栈是否已满 * @return 满返回 true, 否则返回 false */ boolean isFull(); }
链表实现
package com.itheima.Stack; import java.util.Iterator; /** * 基于链表实现的栈,遵循LIFO(后进先出)原则 * 使用虚拟头节点简化栈操作,新元素从头部压入和弹出 * 支持容量限制,当达到容量上限时push操作返回false * * @param <E> 栈中元素的类型 */ public class LinkedListStack<E> implements Stack<E>, Iterable<E> { private final int capacity; // 栈的容量上限 private int size = 0; // 当前栈中元素数量 private final Node<E> head = new Node<>(null, null); // 虚拟头节点 /** * 链表节点类,存储元素值和指向下一节点的引用 */ static class Node<E> { E value; // 节点存储的元素值 Node<E> next; // 指向下一个节点的引用 public Node(E value, Node<E> next) { this.value = value; this.next = next; } } /** * 构造一个具有指定容量的空栈 * * @param capacity 栈的最大容量 * @throws IllegalArgumentException 如果指定容量小于等于0 */ public LinkedListStack(int capacity) { if (capacity <= 0) { throw new IllegalArgumentException("容量必须大于0"); } this.capacity = capacity; } /** * 将元素压入栈顶 * * @param value 要压入的元素 * @return 压入成功返回true;若栈已满返回false * @throws NullPointerException 如果传入的元素为null */ @Override public boolean push(E value) { if (value == null) { throw new NullPointerException("不允许压入null元素"); } if (isFull()) { return false; } else { // 在头部插入新节点 Node<E> node = new Node<>(value, head.next); head.next = node; size++; return true; } } /** * 弹出并返回栈顶元素 * * @return 栈顶元素;若栈为空返回null */ @Override public E pop() { if (isEmpty()) { return null; } Node<E> first = head.next; // 获取头节点的下一个节点(栈顶元素) head.next = first.next; // 头节点指向原栈顶的下一个节点 size--; return first.value; } /** * 返回但不弹出栈顶元素 * * @return 栈顶元素;若栈为空返回null */ @Override public E peek() { if (isEmpty()) { return null; } else { return head.next.value; // 返回头节点的下一个节点的值 } } /** * 判断栈是否为空 * * @return 若栈为空返回true,否则返回false */ @Override public boolean isEmpty() { return head.next == null; // 当头节点的下一个节点为空时栈为空 } /** * 判断栈是否已满 * * @return 若栈达到容量上限返回true,否则返回false */ @Override public boolean isFull() { return size == capacity; // 元素数量达到容量时为满 } /** * 返回一个用于遍历栈中元素的迭代器 * 迭代顺序:从栈顶到栈底(后进先出) * * @return 迭代器实例 */ @Override public Iterator<E> iterator() { return new Iterator<E>() { Node<E> p = head.next; // 从栈顶开始迭代 @Override public boolean hasNext() { return p != null; // 当指针不为空时还有元素 } @Override public E next() { E value = p.value; // 获取当前节点数据 p = p.next; // 指针后移 return value; } }; } }
数组实现
package com.itheima.Stack; import java.util.Iterator; /** * 基于数组实现的栈,遵循LIFO(后进先出)原则 * 使用top指针指示栈顶位置,支持容量限制 * 数组索引0为栈底,top指向栈顶元素的下一个位置 * * @param <E> 栈中元素的类型 */ public class ArrayStack<E> implements Stack<E>, Iterable<E> { private final E[] array; // 存储栈元素的数组 private int top = 0; // 栈顶指针,指示下一个元素入栈的位置 /** * 构造一个具有指定容量的空栈 * * @param capacity 栈的最大容量 * @throws IllegalArgumentException 如果指定容量小于等于0 */ @SuppressWarnings("all") public ArrayStack(int capacity) { if (capacity <= 0) { throw new IllegalArgumentException("容量必须大于0"); } this.array = (E[]) new Object[capacity]; // 创建泛型数组 } /** * 将元素压入栈顶 * * @param value 要压入的元素 * @return 压入成功返回true;若栈已满返回false * @throws NullPointerException 如果传入的元素为null */ @Override public boolean push(E value) { if (value == null) { throw new NullPointerException("不允许压入null元素"); } if (isFull()) { return false; } array[top++] = value; // 将元素放入top位置,然后top加1 return true; } /** * 弹出并返回栈顶元素 * * @return 栈顶元素;若栈为空返回null */ @Override public E pop() { if (isEmpty()) { return null; } return array[--top]; // top减1,然后返回top位置的元素 } /** * 返回但不弹出栈顶元素 * * @return 栈顶元素;若栈为空返回null */ @Override public E peek() { if (isEmpty()) { return null; } return array[top - 1]; // 返回top-1位置的元素(当前栈顶元素) } /** * 判断栈是否为空 * * @return 若栈为空返回true,否则返回false */ @Override public boolean isEmpty() { return top == 0; // 当top为0时栈为空 } /** * 判断栈是否已满 * * @return 若栈达到容量上限返回true,否则返回false */ @Override public boolean isFull() { return top == array.length; // 当top等于数组长度时栈满 } /** * 返回一个用于遍历栈中元素的迭代器 * 迭代顺序:从栈顶到栈底(后进先出) * * @return 迭代器实例 */ @Override public Iterator<E> iterator() { return new Iterator<E>() { int p = top; // 从top开始迭代,指向栈顶元素的下一个位置 @Override public boolean hasNext() { return p > 0; // 当p大于0时还有元素 } @Override public E next() { return array[--p]; // p减1,然后返回p位置的元素 } }; } }
题
package com.itheima.Stack; import java.util.LinkedList; /** * 栈的应用算法集合,包含括号匹配、表达式求值、栈与队列模拟等经典算法 * <p> * 每个算法均基于栈数据结构实现,体现了栈在解决"后进先出"逻辑问题中的核心作用 */ public class Stack_E { /** * E1: 有效括号匹配(LeetCode 20) * 使用栈检查字符串中的括号是否有效闭合 * <p> * 算法思路: * 1. 遍历字符串,遇左括号入栈,遇右括号时检查栈顶是否匹配 * 2. 匹配规则:')'对应'(', ']'对应'[', '}'对应'{' * 3. 最终栈为空则所有括号匹配 * * @param s 待检查的字符串 * @return 括号有效返回true,否则返回false */ public boolean isValid(String s) { // 栈容量设为字符串长度的一半+1(最坏情况全为左括号) ArrayStack<Character> stack = new ArrayStack<>(s.length() / 2 + 1); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // 左括号直接入栈 if (c == '(' || c == '[' || c == '{') { stack.push(c); } else { // 右括号需检查栈顶是否匹配 // 栈非空且栈顶匹配时弹出,否则不合法 if (!stack.isEmpty() && matches(stack.peek(), c)) { stack.pop(); } else { return false; } } } // 最终栈空则所有括号匹配 return stack.isEmpty(); } /** * 判断左右括号是否匹配 */ private boolean matches(char left, char right) { return (left == '(' && right == ')') || (left == '[' && right == ']') || (left == '{' && right == '}'); } /** * E2: 后缀表达式求值(LeetCode 150) * 计算逆波兰表达式的值 * <p> * 算法思路: * 1. 遍历 tokens,遇操作数入栈,遇操作符则弹出两个数计算 * 2. 注意减法和除法的操作数顺序(后弹出的是被减数/被除数) * 3. 最终栈顶为计算结果 * * @param tokens 后缀表达式数组 * @return 计算结果 */ public int evalRPN(String[] tokens) { LinkedList<Integer> stack = new LinkedList<>(); for (String token : tokens) { switch (token) { case "+": // 加法:弹出两个数求和 stack.push(stack.pop() + stack.pop()); break; case "-": // 减法:后弹出的是被减数 int sub1 = stack.pop(); int sub2 = stack.pop(); stack.push(sub2 - sub1); break; case "*": // 乘法 stack.push(stack.pop() * stack.pop()); break; case "/": // 除法:后弹出的是被除数 int div1 = stack.pop(); int div2 = stack.pop(); stack.push(div2 / div1); break; default: // 操作数直接入栈 stack.push(Integer.parseInt(token)); } } return stack.pop(); } /** * E3: 中缀表达式转后缀表达式 * 将中缀表达式转换为后缀表达式(逆波兰表示法) * <p> * 算法思路(Shunting Yard算法): * 1. 遍历字符,遇操作数直接输出 * 2. 遇操作符时,根据优先级弹出栈中优先级不低于当前操作符的操作符 * 3. 左括号入栈,右括号弹出直到遇到左括号 * * @param exp 中缀表达式字符串 * @return 后缀表达式字符串 */ static String infixToSuffix(String exp) { LinkedList<Character> operatorStack = new LinkedList<>(); StringBuilder suffix = new StringBuilder(exp.length()); for (int i = 0; i < exp.length(); i++) { char c = exp.charAt(i); switch (c) { case '+', '-', '*', '/': // 操作符处理:根据优先级决定入栈或弹出 while (!operatorStack.isEmpty() && priority(c) <= priority(operatorStack.peek())) { suffix.append(operatorStack.pop()); } operatorStack.push(c); break; case '(': // 左括号直接入栈 operatorStack.push(c); break; case ')': // 右括号弹出直到遇到左括号 while (!operatorStack.isEmpty() && operatorStack.peek() != '(') { suffix.append(operatorStack.pop()); } if (!operatorStack.isEmpty()) operatorStack.pop(); // 弹出左括号 break; default: // 操作数直接输出 suffix.append(c); } } // 弹出栈中剩余操作符 while (!operatorStack.isEmpty()) { suffix.append(operatorStack.pop()); } return suffix.toString(); } /** * 获取操作符优先级 * @return 优先级数值(数值越大优先级越高) */ static int priority(char op) { return switch (op) { case '(' -> 0; case '+', '-' -> 1; case '*', '/' -> 2; default -> throw new IllegalArgumentException("非法操作符: " + op); }; } /** * E4: 双栈模拟队列(LeetCode 232) * 用两个栈实现队列的先进先出功能 * <p> * 核心思路: * - push栈负责入队,pop栈负责出队 * - 出队时若pop栈为空,则将push栈所有元素倒入pop栈 */ class ArrayStack<E> { private E[] array; private int top = 0; @SuppressWarnings("all") public ArrayStack(int capacity) { array = (E[]) new Object[capacity]; } public boolean push(E value) { if (isFull()) return false; array[top++] = value; return true; } public E pop() { if (isEmpty()) return null; return array[--top]; } public E peek() { if (isEmpty()) return null; return array[top - 1]; } public boolean isEmpty() { return top == 0; } public boolean isFull() { return top == array.length; } } /** * E5: 单队列模拟栈(LeetCode 225) * 用一个队列实现栈的后进先出功能 * <p> * 核心思路: * push时将新元素插入队列尾部,然后将队列前n-1个元素依次出队再入队 * 确保新元素始终在队列头部(栈顶) */ private class ArrayQueue<E> { private E[] array; private int head = 0; private int tail = 0; @SuppressWarnings("all") public ArrayQueue(int capacity) { // 计算大于等于capacity的最小2的幂(避免取模运算) capacity -= 1; capacity |= capacity >> 1; capacity |= capacity >> 2; capacity |= capacity >> 4; capacity |= capacity >> 8; capacity |= capacity >> 16; capacity += 1; array = (E[]) new Object[capacity]; } public boolean offer(E o) { if (isFull()) return false; array[tail] = o; tail = (tail + 1) % array.length; return true; } public E poll() { if (isEmpty()) return null; E value = array[head]; head = (head + 1) % array.length; return value; } public E peek() { if (isEmpty()) return null; return array[head]; } public boolean isEmpty() { return head == tail; } public boolean isFull() { return (tail + 1) % array.length == head; // 修正:正确判断队列满的条件 } } class E05 { private final ArrayQueue<Integer> queue = new ArrayQueue<>(100); private int size = 0; /** * 入栈操作:将元素插入队列尾部,然后将前n-1个元素移到队尾 * 确保新元素始终在队首(栈顶) */ public void push(int x) { queue.offer(x); // 将前size个元素出队再入队,使新元素位于队首 for (int i = 0; i < size; i++) { queue.offer(queue.poll()); } size++; } public int pop() { size--; return queue.poll(); } public int top() { return queue.peek(); } public boolean empty() { return size == 0; } } }
双端队列
BottomCode
collection
package com.itheima.Queue; import java.util.ArrayList; import java.util.List; public class Queue_E { public static void main(String[] args) { // 示例用法 TreeNode root = new TreeNode(3); root.left = new TreeNode(9); root.right = new TreeNode(20); root.right.left = new TreeNode(15); root.right.right = new TreeNode(7); Solution solution = new Solution(); List<List<Integer>> result = solution.levelOrder(root); System.out.println(result); // 输出: [[3], [9, 20], [15, 7]] } /** * E01 二叉树层序遍历 * 使用队列实现按层遍历二叉树,每层元素存储在独立的列表中 */ static class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> result = new ArrayList<>(); if (root == null) { return result; } // 使用自定义链表队列存储待处理的节点 LinkedListQueue<TreeNode> queue = new LinkedListQueue<>(); queue.offer(root); int currentLevelCount = 1; // 当前层的节点数 while (!queue.isEmpty()) { int nextLevelCount = 0; // 下一层的节点数 List<Integer> currentLevel = new ArrayList<>(); // 处理当前层的所有节点 for (int i = 0; i < currentLevelCount; i++) { TreeNode node = queue.poll(); currentLevel.add(node.val); // 将下一层的子节点加入队列 if (node.left != null) { queue.offer(node.left); nextLevelCount++; } if (node.right != null) { queue.offer(node.right); nextLevelCount++; } } // 更新当前层节点数为下一层的节点数 currentLevelCount = nextLevelCount; result.add(currentLevel); } return result; } } /** * 二叉树节点定义 */ static class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } /** * 自定义链表队列实现 * @param <E> 队列元素类型 */ static class LinkedListQueue<E> { private static class Node<E> { E value; Node<E> next; public Node(E value, Node<E> next) { this.value = value; this.next = next; } } private final Node<E> head = new Node<>(null, null); // 虚拟头节点 private Node<E> tail = head; // 尾指针 private int size = 0; // 当前队列大小 private int capacity = 10000; // 默认容量限制 // 初始化循环链表 { head.next = head; } public LinkedListQueue() { } public LinkedListQueue(int capacity) { this.capacity = capacity; } /** * 向队列尾部添加元素 * @param value 待添加的元素 * @return 添加成功返回true,队列已满返回false */ public boolean offer(E value) { if (isFull()) { return false; } // 创建新节点并添加到队尾 Node<E> newNode = new Node<>(value, head); tail.next = newNode; tail = newNode; size++; return true; } /** * 移除并返回队列头部元素 * @return 队列头部元素,队列为空时返回null */ public E poll() { if (isEmpty()) { return null; } // 获取头节点的下一个节点(真正的队首元素) Node<E> first = head.next; head.next = first.next; // 如果移除的是最后一个元素,重置尾指针 if (first == tail) { tail = head; } size--; return first.value; } /** * 返回队列头部元素但不移除 * @return 队列头部元素,队列为空时返回null */ public E peek() { if (isEmpty()) { return null; } return head.next.value; } /** * 判断队列是否为空 * @return 队列为空返回true,否则返回false */ public boolean isEmpty() { return head == tail; } /** * 判断队列是否已满 * @return 队列已满返回true,否则返回false */ public boolean isFull() { return size == capacity; } } }
Map
interface Map_
package _Collection.Map; import _Collection.Collection_; import java.util.Set; /** * Map接口定义了键值对映射的集合规范。 * 每个键最多只能映射到一个值,且键不能重复。 * Map不直接继承Collection接口,但可以通过keySet()、values()或entrySet() * 视图将其视为Collection。 * * <p>Map接口提供了三种集合视图: * <ul> * <li>键集(keySet()):包含所有键的Set</li> * <li>值集(values()):包含所有值的Collection</li> * <li>键值对集(entrySet()):包含所有映射关系的Set</li> * </ul> * * <p>注意: * 1. 某些Map实现允许null键和null值(如HashMap),而其他实现不允许(如TreeMap) * 2. 未明确指定时,Map的顺序是未定义的(如HashMap),但有序Map(如TreeMap)会保持特定顺序 * 3. 所有修改操作都是可选的,实现类可选择不支持某些操作 * * @param <K> 键的类型 * @param <V> 值的类型 * @author 豆包编程助手 * @see HashMap_ * @see TreeMap_ * @since 1.0 */ public interface Map_<K, V> { /** * 返回此Map中键值对的数量。 * 如果Map包含超过Integer.MAX_VALUE个元素,则返回Integer.MAX_VALUE。 * * @return 此Map中键值对的数量 */ int size(); /** * 判断此Map是否为空。 * * @return 如果此Map不包含任何键值对,则返回true */ boolean isEmpty(); /** * 判断此Map是否包含指定键的映射关系。 * * @param key 要检查的键 * @return 如果此Map包含指定键的映射关系,则返回true * @throws ClassCastException 如果指定键的类型与此Map不兼容 * @throws NullPointerException 如果指定键为null,并且此Map不允许null键 */ boolean containsKey(Object key); /** * 判断此Map是否包含指定值的映射关系。 * 更确切地说,判断是否存在至少一个值v,使得 * (value==null ? v==null : value.equals(v))。 * 此操作的时间复杂度可能较高,取决于具体实现。 * * @param value 要检查的值 * @return 如果此Map包含至少一个值的映射关系,则返回true * @throws ClassCastException 如果指定值的类型与此Map不兼容 * @throws NullPointerException 如果指定值为null,并且此Map不允许null值 */ boolean containsValue(Object value); /** * 返回指定键所映射的值;如果此Map不包含该键的映射关系,则返回null。 * 如果返回null,并不一定表示此Map不包含该键的映射关系; * 也可能是该键映射的值为null。使用containsKey()方法可以区分这两种情况。 * * @param key 要获取值的键 * @return 指定键所映射的值,或null(如果映射关系不存在) * @throws ClassCastException 如果指定键的类型与此Map不兼容 * @throws NullPointerException 如果指定键为null,并且此Map不允许null键 */ V get(Object key); /** * 将指定值与此Map中的指定键关联。 * 如果Map先前包含该键的映射关系,则旧值将被指定值替换。 * 如果Map不包含该键的映射关系,则创建新的映射关系。 * * @param key 要关联值的键 * @param value 要与指定键关联的值 * @return 与key关联的旧值,或null(如果没有旧值) * @throws UnsupportedOperationException 如果此Map不支持put操作 * @throws ClassCastException 如果指定键或值的类型与此Map不兼容 * @throws NullPointerException 如果指定键或值为null,并且此Map不允许null键或值 * @throws IllegalArgumentException 如果指定键或值的某些属性阻止其存储在此Map中 */ V put(K key, V value); /** * 移除指定键的映射关系(如果存在)。 * * @param key 要移除映射关系的键 * @return 与key关联的旧值,或null(如果没有旧值) * @throws UnsupportedOperationException 如果此Map不支持remove操作 * @throws ClassCastException 如果指定键的类型与此Map不兼容 * @throws NullPointerException 如果指定键为null,并且此Map不允许null键 */ V remove(Object key); /** * 从此Map中移除所有映射关系。 * 此操作后,Map将为空。 * * @throws UnsupportedOperationException 如果此Map不支持clear操作 */ void clear(); /** * 返回此Map中包含的键的Set视图。 * 该Set由Map支持,因此对Map的更改会反映在Set中,反之亦然。 * 如果在对Set进行迭代时修改了Map(除了通过迭代器自身的remove操作), * 则迭代结果是未定义的。Set支持元素移除,通过Iterator.remove、 * Set.remove、removeAll、retainAll和clear操作, * 这些操作会相应地移除Map中的映射关系。它不支持add或addAll操作。 * * @return 此Map中包含的键的Set视图 */ Set<K> keySet(); /** * 返回此Map中包含的值的Collection视图。 * 该Collection由Map支持,因此对Map的更改会反映在Collection中,反之亦然。 * 如果在对Collection进行迭代时修改了Map(除了通过迭代器自身的remove操作), * 则迭代结果是未定义的。Collection支持元素移除,通过Iterator.remove、 * Collection.remove、removeAll、retainAll和clear操作, * 这些操作会相应地移除Map中的映射关系。它不支持add或addAll操作。 * * @return 此Map中包含的值的Collection视图 */ Collection_<V> values(); /** * 返回此Map中包含的映射关系的Set视图。 * 该Set由Map支持,因此对Map的更改会反映在Set中,反之亦然。 * 如果在对Set进行迭代时修改了Map(除了通过迭代器自身的remove操作, * 或通过迭代器返回的Map.Entry上的setValue操作),则迭代结果是未定义的。 * Set支持元素移除,通过Iterator.remove、Set.remove、removeAll、 * retainAll和clear操作,这些操作会相应地移除Map中的映射关系。 * 它不支持add或addAll操作。 * * @return 此Map中包含的映射关系的Set视图 */ Set<Map_.Entry<K, V>> entrySet(); /** * Map中的键值对(条目)。 * 该接口仅用于表示Map中的映射关系,不提供直接的方法来修改Map。 * 通过Map.entrySet()返回的集合的迭代器可以获取这些条目。 * * @param <K> 键的类型 * @param <V> 值的类型 */ interface Entry<K, V> { /** * 返回与此条目关联的键。 * * @return 与此条目关联的键 * @throws IllegalStateException 如果条目已从底层Map中移除 */ K getKey(); /** * 返回与此条目关联的值。 * 如果底层Map已移除该条目(通过迭代器的remove操作), * 则此调用的结果是未定义的。 * * @return 与此条目关联的值 * @throws IllegalStateException 如果条目已从底层Map中移除 */ V getValue(); /** * 用指定值替换与此条目关联的值(可选操作)。 * (写入操作)仅当底层Map支持put操作时才能执行此操作。 * * @param value 要存储在此条目中的新值 * @return 与此条目关联的旧值 * @throws UnsupportedOperationException 如果底层Map不支持put操作 * @throws ClassCastException 如果指定值的类型阻止其存储在底层Map中 * @throws NullPointerException 如果底层Map不允许null值,并且指定值为null * @throws IllegalArgumentException 如果指定值的某些属性阻止其存储在底层Map中 * @throws IllegalStateException 如果条目已从底层Map中移除 */ V setValue(V value); /** * 比较指定对象与此条目是否相等。 * 如果给定对象也是一个Map条目,并且两个条目表示相同的映射关系, * 则返回true。更确切地说,两个条目e1和e2表示相同的映射关系, * 当且仅当: * <pre> * (e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey())) && * (e1.getValue()==null ? e2.getValue()==null : e1.getValue().equals(e2.getValue())) * </pre> * 这确保了equals方法在不同的Map.Entry实现之间正常工作。 * * @param o 要与此条目进行相等性比较的对象 * @return 如果指定对象等于此条目,则返回true */ boolean equals(Object o); /** * 返回此Map条目的哈希码值。 * Map条目的哈希码定义为: * <pre> * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ * (e.getValue()==null ? 0 : e.getValue().hashCode()) * </pre> * 这确保了e1.equals(e2)意味着e1.hashCode()==e2.hashCode(), * 符合Object.hashCode()的通用契约。 * * @return 此Map条目的哈希码值 * @see Object#hashCode() * @see Object#equals(Object) * @see #equals(Object) */ int hashCode(); } }
HashMap_
package _Collection.Map; import java.util.HashMap; import java.util.Objects; public class HashMap_ <K,V>{ private static final int DEFAULT_INITIAL_CAPACITY = 16; private static final float DEFAULT_LOAD_FACTOR = 0.75f; private static final int TREEIFT_THRESHOLD = 8; private static final int MIN_TREEIFY_CAPACITY = 64; transient Node<K,V> [] table; private int size; private int threshold; static class Node<K,V> implements Map_.Entry<K,V>{ final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V newValue) { V oldValue = this.value; this.value = newValue; return oldValue; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Node<?, ?> node = (Node<?, ?>) o; return hash == node.hash && Objects.equals(key, node.key); } @Override public int hashCode() { return Objects.hash(hash, key); } static class TreeNode<K,V> extends Node<K,V>{ TreeNode<K,V> parent; TreeNode<K,V> left; TreeNode<K,V> right; int red; TreeNode(int hash, K key, V value, Node<K, V> next) { super(hash, key, value, next); } } public HashMap_() { threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); } } }
package _Collection.Map; import java.util.HashMap; import java.util.Objects; /** * 自定义哈希表实现,模仿Java的HashMap功能 * 支持键值对存储,使用链地址法解决哈希冲突 * 当链表长度超过8且容量≥64时转换为红黑树 * * @param <K> 键的类型 * @param <V> 值的类型 */ public class HashMap_<K, V> { private static final int DEFAULT_INITIAL_CAPACITY = 16; // 默认初始容量 private static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认负载因子 private static final int TREEIFY_THRESHOLD = 8; // 链表转树的阈值 private static final int MIN_TREEIFY_CAPACITY = 64; // 转树的最小容量 transient Node<K, V>[] table; // 哈希表数组 private int size; // 键值对数量 private int threshold; // 扩容阈值 = capacity * loadFactor private final float loadFactor; // 负载因子 /** * 链表节点结构 */ static class Node<K, V> implements Map_.Entry<K, V> { final int hash; // 键的哈希值 final K key; // 键 V value; // 值 Node<K, V> next; // 指向下一个节点的引用 Node(int hash, K key, V value, Node<K, V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V newValue) { V oldValue = this.value; this.value = newValue; return oldValue; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Node<?, ?> node = (Node<?, ?>) o; // 修复:增加value比较 return hash == node.hash && Objects.equals(key, node.key) && Objects.equals(value, node.value); } @Override public int hashCode() { // 修复:使用key和value共同生成哈希值 return Objects.hash(key, value); } @Override public String toString() { return key + "=" + value; } } /** * 红黑树节点结构 */ static class TreeNode<K, V> extends Node<K, V> { TreeNode<K, V> parent; // 父节点 TreeNode<K, V> left; // 左子节点 TreeNode<K, V> right; // 右子节点 TreeNode<K, V> prev; // 前驱节点 boolean red; // 颜色标记 TreeNode(int hash, K key, V value, Node<K, V> next) { super(hash, key, value, next); } } /** * 默认构造函数,使用默认初始容量和负载因子 */ public HashMap_() { this.loadFactor = DEFAULT_LOAD_FACTOR; // 修复:初始化时不应设置threshold,首次put时才初始化table // threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); } /** * 指定初始容量的构造函数 */ public HashMap_(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } /** * 指定初始容量和负载因子的构造函数 */ public HashMap_(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > 1 << 30) initialCapacity = 1 << 30; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; // 修复:使用tableSizeFor计算正确的初始容量 this.threshold = tableSizeFor(initialCapacity); } /** * 计算大于等于cap的最小2的幂 */ private static int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= 1 << 30) ? 1 << 30 : n + 1; } /** * 计算键的哈希值,扰动函数 */ static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } /** * 返回键值对数量 */ public int size() { return size; } /** * 判断是否为空 */ public boolean isEmpty() { return size == 0; } /** * 向Map中添加键值对 */ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** * 实际实现put的方法 */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K, V>[] tab; Node<K, V> p; int n, i; // 初始化table或扩容 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // 计算索引位置,若该位置为空则直接插入 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K, V> e; K k; // 如果首节点的键匹配,记录该节点 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; // 如果是树节点,调用树的插入方法 else if (p instanceof TreeNode) e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value); else { // 遍历链表 for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); // 如果链表长度达到树化阈值,转换为红黑树 if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); break; } // 如果找到匹配的键,退出循环 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } // 如果键已存在,根据onlyIfAbsent决定是否更新值 if (e != null) { V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } // 增加键值对数量,如果超过阈值则扩容 ++size; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; } /** * 创建新节点 */ Node<K, V> newNode(int hash, K key, V value, Node<K, V> next) { return new Node<>(hash, key, value, next); } /** * 链表转红黑树 */ final void treeifyBin(Node<K, V>[] tab, int hash) { int n, index; Node<K, V> e; // 如果table容量小于最小树化容量,优先扩容 if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) resize(); else if ((e = tab[index = (n - 1) & hash]) != null) { // 链表转红黑树的具体实现 // ... } } /** * 调整哈希表大小 */ final Node<K, V>[] resize() { Node<K, V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { // 如果旧容量已达到最大值,不再扩容 if (oldCap >= 1 << 30) { threshold = Integer.MAX_VALUE; return oldTab; } // 容量翻倍 else if ((newCap = oldCap << 1) < 1 << 30 && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // 阈值翻倍 } else if (oldThr > 0) // 初始容量由threshold指定 newCap = oldThr; else { // 使用默认值初始化 newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); } if (newThr == 0) { float ft = (float) newCap * loadFactor; newThr = (newCap < 1 << 30 && ft < (float) 1 << 30 ? (int) ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"unchecked"}) Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap]; table = newTab; // 重新哈希所有键值对 if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Node<K, V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) ((TreeNode<K, V>) e).split(this, newTab, j, oldCap); else { // 链表重哈希优化 Node<K, V> loHead = null, loTail = null; Node<K, V> hiHead = null, hiTail = null; Node<K, V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; } /** * 从Map中获取键对应的值 */ public V get(Object key) { Node<K, V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } /** * 实际实现get的方法 */ final Node<K, V> getNode(int hash, Object key) { Node<K, V>[] tab; Node<K, V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { // 检查首节点 if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { // 如果是树节点,调用树的查找方法 if (first instanceof TreeNode) return ((TreeNode<K, V>) first).getTreeNode(hash, key); // 遍历链表 do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; } /** * 判断Map是否包含指定键 */ public boolean containsKey(Object key) { return getNode(hash(key), key) != null; } /** * 从Map中移除键对应的值 */ public V remove(Object key) { Node<K, V> e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; } /** * 实际实现remove的方法 */ final Node<K, V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) { Node<K, V>[] tab; Node<K, V> p; int n, index; if ((tab = table) != null && (n = tab.length) > 0 && (p = tab[index = (n - 1) & hash]) != null) { Node<K, V> node = null, e; K k; V v; // 检查首节点 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) node = p; else if ((e = p.next) != null) { // 如果是树节点,调用树的查找方法 if (p instanceof TreeNode) node = ((TreeNode<K, V>) p).getTreeNode(hash, key); else { // 遍历链表 do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { node = e; break; } p = e; } while ((e = e.next) != null); } } // 如果找到节点,根据matchValue决定是否移除 if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) { if (node instanceof TreeNode) ((TreeNode<K, V>) node).removeTreeNode(this, tab, movable); else if (node == p) tab[index] = node.next; else p.next = node.next; // 减少键值对数量 --size; afterNodeRemoval(node); return node; } } return null; } /** * 清空Map */ public void clear() { Node<K, V>[] tab; if ((tab = table) != null && size > 0) { size = 0; for (int i = 0; i < tab.length; ++i) tab[i] = null; } } /** * 判断Map是否包含指定值 */ public boolean containsValue(Object value) { Node<K, V>[] tab; V v; if ((tab = table) != null && size > 0) { // 遍历所有桶 for (int i = 0; i < tab.length; ++i) { // 遍历桶中的每个节点 for (Node<K, V> e = tab[i]; e != null; e = e.next) { if ((v = e.value) == value || (value != null && value.equals(v))) return true; } } } return false; } // 以下为钩子方法,子类可重写 void afterNodeAccess(Node<K, V> p) { } void afterNodeInsertion(boolean evict) { } void afterNodeRemoval(Node<K, V> p) { } }
HashTable
package _Collection; import java.util.*; /** * 自定义 Hashtable 实现,使用哈希表存储键值对,支持线程安全 */ public class Hashtable_<K, V> implements Map_<K, V> { // 默认初始容量 private static final int DEFAULT_INITIAL_CAPACITY = 11; // 最大容量 private static final int MAXIMUM_CAPACITY = 1 << 30; // 默认负载因子 private static final float DEFAULT_LOAD_FACTOR = 0.75f; // 哈希表数组 private Entry<?, ?>[] table; // 键值对数量 private int count; // 扩容阈值 private int threshold; // 负载因子 private float loadFactor; // 结构修改次数 private int modCount = 0; // 哈希表节点类 private static class Entry<K, V> implements Map_.Entry<K, V> { final int hash; final K key; V value; Entry<K, V> next; protected Entry(int hash, K key, V value, Entry<K, V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V value) { if (value == null) throw new NullPointerException(); V oldValue = this.value; this.value = value; return oldValue; } @Override public boolean equals(Object o) { if (!(o instanceof Map_.Entry)) return false; Map_.Entry<?, ?> e = (Map_.Entry<?, ?>)o; return (key==null ? e.getKey()==null : key.equals(e.getKey())) && (value==null ? e.getValue()==null : value.equals(e.getValue())); } @Override public int hashCode() { return hash ^ (value==null ? 0 : value.hashCode()); } @Override public String toString() { return key.toString()+"="+value.toString(); } } // 构造函数 public Hashtable_() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } public Hashtable_(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } public Hashtable_(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAXIMUM_CAPACITY + 1); } // 计算哈希值 private int hash(Object k) { return k.hashCode() & 0x7FFFFFFF; } // 计算索引 private int indexFor(int h, int length) { return (h % length); } @Override public synchronized int size() { return count; } @Override public synchronized boolean isEmpty() { return count == 0; } @Override public synchronized boolean containsKey(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false; } @Override public synchronized boolean containsValue(Object value) { Entry<?,?> tab[] = table; if (value == null) throw new NullPointerException(); for (int i = tab.length ; i-- > 0 ;) { for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; } @Override public synchronized V get(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null; } @Override public synchronized V put(K key, V value) { // 不允许 null 键或值 if (key == null || value == null) { throw new NullPointerException(); } // 确保键不存在 Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K, V> entry = (Entry<K, V>)tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } // 添加新条目 addEntry(hash, key, value, index); return null; } private void addEntry(int hash, K key, V value, int index) { modCount++; Entry<?,?> tab[] = table; if (count >= threshold) { // 扩容 rehash(); tab = table; hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length; } // 创建新条目 @SuppressWarnings("unchecked") Entry<K, V> e = (Entry<K, V>) tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; } // 扩容方法 @SuppressWarnings("unchecked") protected void rehash() { int oldCapacity = table.length; Entry<?,?>[] oldMap = table; // 新容量为旧容量的2倍+1 int newCapacity = (oldCapacity << 1) + 1; if (newCapacity > MAXIMUM_CAPACITY) { if (oldCapacity == MAXIMUM_CAPACITY) return; newCapacity = MAXIMUM_CAPACITY; } Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); table = newMap; // 重新哈希所有条目 for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K, V> old = (Entry<K, V>)oldMap[i] ; old != null ; ) { Entry<K, V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry<K, V>)newMap[index]; newMap[index] = e; } } } @Override public synchronized V remove(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K, V> e = (Entry<K, V>)tab[index]; for(Entry<K, V> prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; } @Override public synchronized void clear() { Entry<?,?> tab[] = table; modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; } @Override public synchronized Set_<K> keySet() { return new KeySet(); } @Override public synchronized Collection_<V> values() { return new Values(); } @Override public synchronized Set_<Map_.Entry<K, V>> entrySet() { return new EntrySet(); } // KeySet 视图 private class KeySet extends AbstractSet_<K> { @Override public Iterator<K> iterator() { return new KeyIterator(); } @Override public int size() { return count; } @Override public boolean contains(Object o) { return containsKey(o); } @Override public boolean remove(Object o) { return Hashtable_.this.remove(o) != null; } @Override public void clear() { Hashtable_.this.clear(); } } // Values 视图 private class Values extends AbstractCollection_<V> { @Override public Iterator<V> iterator() { return new ValueIterator(); } @Override public int size() { return count; } @Override public boolean contains(Object o) { return containsValue(o); } @Override public void clear() { Hashtable_.this.clear(); } } // EntrySet 视图 private class EntrySet extends AbstractSet_<Map_.Entry<K, V>> { @Override public Iterator<Map_.Entry<K, V>> iterator() { return new EntryIterator(); } @Override public int size() { return count; } @Override public boolean contains(Object o) { if (!(o instanceof Map_.Entry)) return false; Map_.Entry<?,?> entry = (Map_.Entry<?,?>)o; Object key = entry.getKey(); Entry<?,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index]; e != null; e = e.next) if (e.hash == hash && e.equals(entry)) return true; return false; } @Override public boolean remove(Object o) { if (!(o instanceof Map_.Entry)) return false; Map_.Entry<?,?> entry = (Map_.Entry<?,?>)o; Object key = entry.getKey(); Entry<?,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K, V>[] tab2 = (Entry<K, V>[]) tab; for (Entry<K, V> e = tab2[index], prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.equals(entry)) { modCount++; if (prev != null) prev.next = e.next; else tab2[index] = e.next; count--; e.value = null; return true; } } return false; } @Override public void clear() { Hashtable_.this.clear(); } } // 迭代器基类 private abstract class HashIterator<E> implements Iterator<E> { Entry<?,?>[] table = Hashtable_.this.table; int index = table.length; Entry<?,?> entry = null; Entry<?,?> lastReturned = null; int expectedModCount = modCount; @Override public boolean hasNext() { while (entry == null && index > 0) entry = table[--index]; return entry != null; } @Override public E next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); while (entry == null && index > 0) entry = table[--index]; if (entry == null) throw new NoSuchElementException(); lastReturned = entry; entry = entry.next; return createNext(lastReturned); } protected abstract E createNext(Entry<?,?> e); @Override public void remove() { if (lastReturned == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); synchronized(Hashtable_.this) { Entry<?,?>[] tab = Hashtable_.this.table; int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K, V> e = (Entry<K, V>)tab[index]; for(Entry<K, V> prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { modCount++; if (prev == null) tab[index] = e.next; else prev.next = e.next; count--; lastReturned = null; return; } } throw new ConcurrentModificationException(); } } } // KeyIterator private class KeyIterator extends HashIterator<K> { @Override protected K createNext(Entry<?,?> e) { return (K)e.key; } } // ValueIterator private class ValueIterator extends HashIterator<V> { @Override protected V createNext(Entry<?,?> e) { return (V)e.value; } } // EntryIterator private class EntryIterator extends HashIterator<Map_.Entry<K, V>> { @Override protected Map_.Entry<K, V> createNext(Entry<?,?> e) { return (Map_.Entry<K, V>)e; } } @Override public String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder(); sb.append('{'); Iterator<Map_.Entry<K, V>> it = entrySet().iterator(); for (int i = 0; ; i++) { Map_.Entry<K, V> e = it.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key.toString()); sb.append('='); sb.append(value == this ? "(this Map)" : value.toString()); if (i == max) return sb.append('}').toString(); sb.append(", "); } } }
/* * Copyright (c) 1994, 2023, Oracle和/或其附属公司。保留所有权利。 * 请勿更改或删除版权声明或本文件头部。 * * 本代码是免费软件;您可以根据GNU通用公共许可证第2版的条款重新分发和/或修改它, * 该许可证仅由自由软件基金会发布。Oracle在随附此代码的LICENSE文件中指定了这个 * 特定文件受"Classpath"异常的约束。 * * 本代码的分发是希望它会有用,但没有任何保证;甚至没有对适销性或特定用途适用性的默示保证。 * 有关GNU通用公共许可证第2版的更多详细信息(随附此代码的LICENSE文件中包含一份副本)。 * * 您应该已经收到了GNU通用公共许可证第2版的副本;如果没有,请写信给自由软件基金会, * 地址:美国马萨诸塞州波士顿市富兰克林街51号,第五层,邮编02110-1301。 * * 如果您需要额外的信息或有任何问题,请联系Oracle,地址:美国加利福尼亚州红杉海岸市甲骨文公园500号, * 或访问www.oracle.com。 */ package java.util; import java.io.*; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.BiFunction; import jdk.internal.access.SharedSecrets; /** * 此类实现哈希表,将键映射到值。任何非{@code null}对象都可以用作键或值。<p> * * 要成功地在哈希表中存储和检索对象,用作键的对象必须实现{@code hashCode} * 方法和{@code equals}方法。<p> * * {@code Hashtable}的实例有两个影响其性能的参数:<i>初始容量</i>和<i>负载因子</i>。 * <i>容量</i>是哈希表中的<i>桶</i>数量,而<i>初始容量</i>只是创建哈希表时的容量。 * 请注意,哈希表是<i>开放</i>的:在发生"哈希冲突"的情况下,单个桶存储多个条目,必须按顺序搜索这些条目。 * <i>负载因子</i>是衡量哈希表在自动增加容量之前允许的填充程度的指标。初始容量和负载因子参数只是对实现的提示。 * 关于何时以及是否调用rehash方法的具体细节取决于实现。<p> * * 通常,默认负载因子(0.75)在时间和空间成本之间提供了良好的平衡。较高的值会减少空间开销, * 但会增加查找条目的时间成本(这反映在大多数{@code Hashtable}操作中,包括{@code get}和{@code put})。<p> * * 初始容量控制着浪费空间和{@code rehash}操作需求之间的权衡,rehash操作非常耗时。 * 如果初始容量大于{@code Hashtable}将包含的最大条目数除以其负载因子,则<i>永远不会</i>发生rehash操作。 * 但是,将初始容量设置得过高会浪费空间。<p> * * 如果要向{@code Hashtable}中添加许多条目,创建具有足够大初始容量的哈希表可以允许 * 比按需自动rehash更高效地插入条目。<p> * * 此示例创建一个数字的哈希表。它使用数字的名称作为键: * <pre> {@code * Hashtable<String, Integer> numbers * = new Hashtable<String, Integer>(); * numbers.put("one", 1); * numbers.put("two", 2); * numbers.put("three", 3);}</pre> * * <p>要检索数字,请使用以下代码: * <pre> {@code * Integer n = numbers.get("two"); * if (n != null) { * System.out.println("two = " + n); * }}</pre> * * <p>由所有此类的"集合视图方法"返回的集合的{@code iterator}方法返回的迭代器是 * <em>快速失败</em>的:如果在创建迭代器后以任何方式对Hashtable进行结构修改(除了通过迭代器自身的{@code remove}方法), * 迭代器将抛出{@link ConcurrentModificationException}。 * 因此,在并发修改的情况下,迭代器会快速而干净地失败,而不是在未来不确定的时间冒着任意的、非确定性行为的风险。 * Hashtable的{@link #keys keys}和{@link #elements elements}方法返回的Enumeration * <em>不是</em>快速失败的;如果在创建枚举后对Hashtable进行结构修改,枚举的结果是未定义的。 * * <p>请注意,迭代器的快速失败行为不能得到保证,因为一般来说,在存在未同步的并发修改时, * 不可能做出任何硬性保证。快速失败迭代器会尽力抛出{@code ConcurrentModificationException}。 * 因此,编写依赖于此异常来确保其正确性的程序是错误的:<i>迭代器的快速失败行为应仅用于检测错误。</i> * * <p>从Java 2平台v1.2开始,此类被改造为实现{@link Map}接口,使其成为 * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework"> * Java集合框架</a>的成员。与新的集合实现不同,{@code Hashtable}是同步的。 * 如果不需要线程安全的实现,建议使用{@link HashMap}代替{@code Hashtable}。 * 如果需要线程安全的高并发实现,则建议使用{@link java.util.concurrent.ConcurrentHashMap}代替 * {@code Hashtable}。 * * @param <K> 此映射维护的键的类型 * @param <V> 映射值的类型 * * @author Arthur van Hoff * @author Josh Bloch * @author Neal Gafter * @see Object#equals(java.lang.Object) * @see Object#hashCode() * @see Hashtable#rehash() * @see Collection * @see Map * @see HashMap * @see TreeMap * @since 1.0 */ public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable { /** * 哈希表数据。 */ private transient Entry<?,?>[] table; /** * 哈希表中的条目总数。 */ private transient int count; /** * 当哈希表的大小超过此阈值时会进行rehash。(此字段的值为(int)(capacity * loadFactor)。) * * @serial */ private int threshold; /** * 哈希表的负载因子。 * * @serial */ private float loadFactor; /** * 此Hashtable被结构修改的次数 * 结构修改是指改变Hashtable中的条目数或以其他方式修改其内部结构(例如rehash)。 * 此字段用于使Hashtable的集合视图上的迭代器快速失败。(请参阅ConcurrentModificationException。) */ private transient int modCount = 0; /** 使用JDK 1.0.2的serialVersionUID以实现互操作性 */ @java.io.Serial private static final long serialVersionUID = 1421746759512286392L; /** * 构造一个新的、空的哈希表,具有指定的初始容量和指定的负载因子。 * * @param initialCapacity 哈希表的初始容量。 * @param loadFactor 哈希表的负载因子。 * @throws IllegalArgumentException 如果初始容量小于零,或者负载因子为非正数。 */ public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("非法容量: " + initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("非法负载因子: " + loadFactor); if (initialCapacity == 0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); } /** * 构造一个新的、空的哈希表,具有指定的初始容量和默认负载因子(0.75)。 * * @param initialCapacity 哈希表的初始容量。 * @throws IllegalArgumentException 如果初始容量小于零。 */ public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } /** * 构造一个新的、空的哈希表,具有默认初始容量(11)和负载因子(0.75)。 */ public Hashtable() { this(11, 0.75f); } /** * 构造一个新的哈希表,其映射与给定的Map相同。 * 哈希表的创建具有足够的初始容量来容纳给定Map中的映射和默认负载因子(0.75)。 * * @param t 其映射将被放置在此映射中的map。 * @throws NullPointerException 如果指定的map为null。 * @since 1.2 */ @SuppressWarnings("this-escape") public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2 * t.size(), 11), 0.75f); putAll(t); } /** * 从{@link Properties}链式调用的构造函数保持Hashtable字段未初始化,因为它们未被使用。 * * @param dummy 一个虚拟参数 */ Hashtable(Void dummy) {} /** * 返回此哈希表中的键数。 * * @return 此哈希表中的键数。 */ public synchronized int size() { return count; } /** * 测试此哈希表是否没有键映射到值。 * * @return 如果此哈希表没有键映射到值,则为{@code true}; * 否则为{@code false}。 */ public synchronized boolean isEmpty() { return count == 0; } /** * 返回此哈希表中键的枚举。 * 使用返回对象上的Enumeration方法按顺序获取键。 * 如果在枚举键的过程中对哈希表进行了结构修改,则枚举的结果是未定义的。 * * @return 此哈希表中键的枚举。 * @see Enumeration * @see #elements() * @see #keySet() * @see Map */ public synchronized Enumeration<K> keys() { return this.<K>getEnumeration(KEYS); } /** * 返回此哈希表中值的枚举。 * 使用返回对象上的Enumeration方法按顺序获取元素。 * 如果在枚举值的过程中对哈希表进行了结构修改,则枚举的结果是未定义的。 * * @return 此哈希表中值的枚举。 * @see java.util.Enumeration * @see #keys() * @see #values() * @see Map */ public synchronized Enumeration<V> elements() { return this.<V>getEnumeration(VALUES); } /** * 测试此哈希表中是否有某个键映射到指定的值。 * 此操作比{@link #containsKey containsKey}方法更昂贵。 * * <p>注意,此方法在功能上与{@link #containsValue containsValue}相同(这是 * 集合框架中{@link Map}接口的一部分)。 * * @param value 要搜索的值 * @return 如果此哈希表中某个键映射到{@code value}参数(由{@code equals}方法确定),则为{@code true}; * 否则为{@code false}。 * @throws NullPointerException 如果值为{@code null} */ public synchronized boolean contains(Object value) { if (value == null) { throw new NullPointerException(); } Entry<?,?> tab[] = table; for (int i = tab.length; i-- > 0;) { for (Entry<?,?> e = tab[i]; e != null; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; } /** * 如果此哈希表将一个或多个键映射到此值,则返回true。 * * <p>注意,此方法在功能上与{@link #contains contains}相同(它早于{@link Map}接口)。 * * @param value 要测试其在此哈希表中存在的值 * @return 如果此映射将一个或多个键映射到指定值,则为{@code true} * @throws NullPointerException 如果值为{@code null} * @since 1.2 */ public boolean containsValue(Object value) { return contains(value); } /** * 测试指定的对象是否是此哈希表中的键。 * * @param key 可能的键 * @return 如果指定的对象是此哈希表中的键(由{@code equals}方法确定),则为{@code true};否则为{@code false}。 * @throws NullPointerException 如果键为{@code null} * @see #contains(Object) */ public synchronized boolean containsKey(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index]; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false; } /** * 返回指定键映射到的值, * 如果此映射不包含该键的映射,则返回{@code null}。 * * <p>更正式地说,如果此映射包含从键{@code k}到值{@code v}的映射,使得{@code (key.equals(k))}, * 则此方法返回{@code v};否则返回{@code null}。(最多有一个这样的映射。) * * @param key 要返回其关联值的键 * @return 指定键映射到的值,或 * 如果此映射不包含该键的映射,则为{@code null} * @throws NullPointerException 如果指定的键为null * @see #put(Object, Object) */ @SuppressWarnings("unchecked") public synchronized V get(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index]; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null; } /** * 要分配的数组的最大大小。 * 一些VM在数组中保留一些头字。 * 尝试分配更大的数组可能导致 * OutOfMemoryError: 请求的数组大小超过VM限制 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 增加此哈希表的容量并在内部重新组织它,以更高效地容纳和访问其条目。 * 当哈希表中的键数超过此哈希表的容量和负载因子时,会自动调用此方法。 */ @SuppressWarnings("unchecked") protected void rehash() { int oldCapacity = table.length; Entry<?,?>[] oldMap = table; // 考虑溢出的代码 int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) // 继续使用MAX_ARRAY_SIZE个桶 return; newCapacity = MAX_ARRAY_SIZE; } Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); table = newMap; for (int i = oldCapacity; i-- > 0;) { for (Entry<K,V> old = (Entry<K,V>)oldMap[i]; old != null;) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry<K,V>)newMap[index]; newMap[index] = e; } } } private void addEntry(int hash, K key, V value, int index) { Entry<?,?> tab[] = table; if (count >= threshold) { // 如果超过阈值,对表进行rehash rehash(); tab = table; hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length; } // 创建新条目 @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; modCount++; } /** * 将指定的{@code key}映射到指定的 * {@code value}到此哈希表中。键和值都不能为{@code null}。<p> * * 可以通过使用等于原始键的键调用{@code get}方法来检索值。 * * @param key 哈希表键 * @param value 值 * @return 此哈希表中指定键的先前值, * 如果没有先前值,则为{@code null} * @throws NullPointerException 如果键或值为 * {@code null} * @see Object#equals(Object) * @see #get(Object) */ public synchronized V put(K key, V value) { // 确保值不为null if (value == null) { throw new NullPointerException(); } // 确保键不在哈希表中 Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for (; entry != null; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; } /** * 从此哈希表中移除键(及其对应的值)。 * 如果键不在哈希表中,此方法不执行任何操作。 * * @param key 需要移除的键 * @return 键在此哈希表中映射到的值, * 如果键没有映射,则为{@code null} * @throws NullPointerException 如果键为{@code null} */ public synchronized V remove(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } modCount++; count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; } /** * 将指定映射中的所有映射复制到此哈希表中。 * 这些映射将替换此哈希表中对指定映射中当前任何键的现有映射。 * * @param t 要存储在此映射中的映射 * @throws NullPointerException 如果指定的映射为null * @since 1.2 */ public synchronized void putAll(Map<? extends K, ? extends V> t) { for (Map.Entry<? extends K, ? extends V> e : t.entrySet()) put(e.getKey(), e.getValue()); } /** * 清空此哈希表,使其不包含任何键。 */ public synchronized void clear() { Entry<?,?> tab[] = table; for (int index = tab.length; --index >= 0;) tab[index] = null; modCount++; count = 0; } /** * 创建此哈希表的浅拷贝。哈希表本身的所有结构都被复制, * 但键和值不会被克隆。这是一个相对昂贵的操作。 * * @return 哈希表的克隆 */ public synchronized Object clone() { Hashtable<?,?> t = cloneHashtable(); t.table = new Entry<?,?>[table.length]; for (int i = table.length; i-- > 0;) { t.table[i] = (table[i] != null) ? (Entry<?,?>) table[i].clone() : null; } t.keySet = null; t.entrySet = null; t.values = null; t.modCount = 0; return t; } /** 调用super.clone() */ final Hashtable<?,?> cloneHashtable() { try { return (Hashtable<?,?>)super.clone(); } catch (CloneNotSupportedException e) { // 这不应该发生,因为我们是Cloneable throw new InternalError(e); } } /** * 返回此{@code Hashtable}对象的字符串表示形式,形式为一组条目, * 用大括号括起来,并用ASCII字符"<code> , </code>"(逗号和空格)分隔。 * 每个条目呈现为键、等号{@code =}和关联的元素,其中使用{@code toString}方法 * 将键和元素转换为字符串。 * * @return 此哈希表的字符串表示形式 */ public synchronized String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder(); sb.append('{'); Iterator<Map.Entry<K,V>> it = entrySet().iterator(); for (int i = 0;; i++) { Map.Entry<K,V> e = it.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(此映射)" : key.toString()); sb.append('='); sb.append(value == this ? "(此映射)" : value.toString()); if (i == max) return sb.append('}').toString(); sb.append(", "); } } private <T> Enumeration<T> getEnumeration(int type) { if (count == 0) { return Collections.emptyEnumeration(); } else { return new Enumerator<>(type, false); } } private <T> Iterator<T> getIterator(int type) { if (count == 0) { return Collections.emptyIterator(); } else { return new Enumerator<>(type, true); } } // 视图 /** * 这些字段中的每一个都会在首次请求此视图时初始化以包含相应视图的实例。 * 视图是无状态的,因此没有理由为每个视图创建多个实例。 */ private transient volatile Set<K> keySet; private transient volatile Set<Map.Entry<K,V>> entrySet; private transient volatile Collection<V> values; /** * 返回此映射中包含的键的{@link Set}视图。 * 该集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。 * 如果在集合的迭代过程中修改了映射(除了通过迭代器自身的{@code remove}操作), * 迭代的结果是未定义的。集合支持元素移除, * 通过{@code Iterator.remove}、{@code Set.remove}、 * {@code removeAll}、{@code retainAll}和{@code clear} * 操作从映射中移除相应的映射。它不支持{@code add}或{@code addAll} * 操作。 * * @since 1.2 */ public Set<K> keySet() { if (keySet == null) keySet = Collections.synchronizedSet(new KeySet(), this); return keySet; } private class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return getIterator(KEYS); } public int size() { return count; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return Hashtable.this.remove(o) != null; } public void clear() { Hashtable.this.clear(); } } /** * 返回此映射中包含的映射的{@link Set}视图。 * 该集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。 * 如果在集合的迭代过程中修改了映射(除了通过迭代器自身的{@code remove}操作, * 或通过迭代器返回的映射条目的{@code setValue}操作), * 迭代的结果是未定义的。集合支持元素移除, * 通过{@code Iterator.remove}、{@code Set.remove}、 * {@code removeAll}、{@code retainAll}和{@code clear} * 操作从映射中移除相应的映射。它不支持 * {@code add}或{@code addAll}操作。 * * @since 1.2 */ public Set<Map.Entry<K,V>> entrySet() { if (entrySet == null) entrySet = Collections.synchronizedSet(new EntrySet(), this); return entrySet; } private class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return getIterator(ENTRIES); } public boolean add(Map.Entry<K,V> o) { return super.add(o); } public boolean contains(Object o) { if (!(o instanceof Map.Entry<?, ?> entry)) return false; Object key = entry.getKey(); Entry<?,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index]; e != null; e = e.next) if (e.hash == hash && e.equals(entry)) return true; return false; } public boolean remove(Object o) { if (!(o instanceof Map.Entry<?, ?> entry)) return false; Object key = entry.getKey(); Entry<?,?>[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.equals(entry)) { if (prev != null) prev.next = e.next; else tab[index] = e.next; e.value = null; // 清除以便垃圾回收 modCount++; count--; return true; } } return false; } public int size() { return count; } public void clear() { Hashtable.this.clear(); } } /** * 返回此映射中包含的值的{@link Collection}视图。 * 该集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。 * 如果在集合的迭代过程中修改了映射(除了通过迭代器自身的{@code remove}操作), * 迭代的结果是未定义的。集合支持元素移除, * 通过{@code Iterator.remove}、{@code Collection.remove}、 * {@code removeAll}、{@code retainAll}和{@code clear} * 操作从映射中移除相应的映射。它不支持 * {@code add}或{@code addAll}操作。 * * @since 1.2 */ public Collection<V> values() { if (values == null) values = Collections.synchronizedCollection(new ValueCollection(), this); return values; } private class ValueCollection extends AbstractCollection<V> { public Iterator<V> iterator() { return getIterator(VALUES); } public int size() { return count; } public boolean contains(Object o) { return containsValue(o); } public void clear() { Hashtable.this.clear(); } } // 比较和哈希 /** * 根据Map接口中的定义,将指定的Object与此Map进行相等性比较。 * * @param o 要与此哈希表比较相等性的对象 * @return 如果指定的Object等于此Map,则为true * @see Map#equals(Object) * @since 1.2 */ public synchronized boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map<?, ?> t)) return false; if (t.size() != size()) return false; try { for (Map.Entry<K, V> e : entrySet()) { K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(t.get(key) == null && t.containsKey(key))) return false; } else { if (!value.equals(t.get(key))) return false; } } } catch (ClassCastException | NullPointerException unused) { return false; } return true; } /** * 根据Map接口中的定义,返回此Map的哈希码值。 * * @see Map#hashCode() * @since 1.2 */ public synchronized int hashCode() { /* * 此代码检测计算自引用哈希表的哈希码时引起的递归,并防止 * 否则会导致的栈溢出。这允许某些带有自引用哈希表的1.1时代的 * applet正常工作。此代码滥用loadFactor字段来兼作哈希码 * 计算中的进度标志,以免恶化空间性能。 * 负的负载因子表示哈希码计算正在进行中。 */ int h = 0; if (count == 0 || loadFactor < 0) return h; // 返回零 loadFactor = -loadFactor; // 标记哈希码计算正在进行中 Entry<?,?>[] tab = table; for (Entry<?,?> entry : tab) { while (entry != null) { h += entry.hashCode(); entry = entry.next; } } loadFactor = -loadFactor; // 标记哈希码计算完成 return h; } @Override public synchronized V getOrDefault(Object key, V defaultValue) { V result = get(key); return (null == result) ? defaultValue : result; } @SuppressWarnings("unchecked") @Override public synchronized void forEach(BiConsumer<? super K, ? super V> action) { Objects.requireNonNull(action); // 在表为空的情况下需要显式检查 // 。 final int expectedModCount = modCount; Entry<?, ?>[] tab = table; for (Entry<?, ?> entry : tab) { while (entry != null) { action.accept((K)entry.key, (V)entry.value); entry = entry.next; if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } } @SuppressWarnings("unchecked") @Override public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { Objects.requireNonNull(function); // 在表为空的情况下需要显式检查 // 。 final int expectedModCount = modCount; Entry<K, V>[] tab = (Entry<K, V>[])table; for (Entry<K, V> entry : tab) { while (entry != null) { entry.value = Objects.requireNonNull( function.apply(entry.key, entry.value)); entry = entry.next; if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } } @Override public synchronized V putIfAbsent(K key, V value) { Objects.requireNonNull(value); // 确保键不在哈希表中 Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for (; entry != null; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; if (old == null) { entry.value = value; } return old; } } addEntry(hash, key, value, index); return null; } @Override public synchronized boolean remove(Object key, Object value) { Objects.requireNonNull(value); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) { if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } e.value = null; // 清除以便垃圾回收 modCount++; count--; return true; } } return false; } @Override public synchronized boolean replace(K key, V oldValue, V newValue) { Objects.requireNonNull(oldValue); Objects.requireNonNull(newValue); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { if (e.value.equals(oldValue)) { e.value = newValue; return true; } else { return false; } } } return false; } @Override public synchronized V replace(K key, V value) { Objects.requireNonNull(value); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { V oldValue = e.value; e.value = value; return oldValue; } } return null; } /** * {@inheritDoc} * * <p>此方法将在尽力而为的基础上,如果映射函数在计算期间修改了此映射, * 则抛出{@link java.util.ConcurrentModificationException}。 * * @throws ConcurrentModificationException 如果检测到映射函数修改了此映射 */ @Override public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { Objects.requireNonNull(mappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (; e != null; e = e.next) { if (e.hash == hash && e.key.equals(key)) { // Hashtable不接受null值 return e.value; } } int mc = modCount; V newValue = mappingFunction.apply(key); if (mc != modCount) { throw new ConcurrentModificationException(); } if (newValue != null) { addEntry(hash, key, newValue, index); } return newValue; } /** * {@inheritDoc} * * <p>此方法将在尽力而为的基础上,如果重映射函数在计算期间修改了此映射, * 则抛出{@link java.util.ConcurrentModificationException}。 * * @throws ConcurrentModificationException 如果检测到重映射函数修改了此映射 */ @Override public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { int mc = modCount; V newValue = remappingFunction.apply(key, e.value); if (mc != modCount) { throw new ConcurrentModificationException(); } if (newValue == null) { if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } modCount = mc + 1; count--; } else { e.value = newValue; } return newValue; } } return null; } /** * {@inheritDoc} * * <p>此方法将在尽力而为的基础上,如果重映射函数在计算期间修改了此映射, * 则抛出{@link java.util.ConcurrentModificationException}。 * * @throws ConcurrentModificationException 如果检测到重映射函数修改了此映射 */ @Override public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && Objects.equals(e.key, key)) { int mc = modCount; V newValue = remappingFunction.apply(key, e.value); if (mc != modCount) { throw new ConcurrentModificationException(); } if (newValue == null) { if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } modCount = mc + 1; count--; } else { e.value = newValue; } return newValue; } } int mc = modCount; V newValue = remappingFunction.apply(key, null); if (mc != modCount) { throw new ConcurrentModificationException(); } if (newValue != null) { addEntry(hash, key, newValue, index); } return newValue; } /** * {@inheritDoc} * * <p>此方法将在尽力而为的基础上,如果重映射函数在计算期间修改了此映射, * 则抛出{@link java.util.ConcurrentModificationException}。 * * @throws ConcurrentModificationException 如果检测到重映射函数修改了此映射 */ @Override public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.key.equals(key)) { int mc = modCount; V newValue = remappingFunction.apply(e.value, value); if (mc != modCount) { throw new ConcurrentModificationException(); } if (newValue == null) { if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } modCount = mc + 1; count--; } else { e.value = newValue; } return newValue; } } if (value != null) { addEntry(hash, key, value, index); } return value; } /** * 将Hashtable的状态保存到流(即序列化它)。 * * @serialData Hashtable的<i>容量</i>(桶数组的长度)被发出(int),然后是 * Hashtable的<i>大小</i>(键值映射的数量),然后是每个键值映射的键(Object)和值(Object) * 键值映射以无特定顺序发出。 */ @java.io.Serial private void writeObject(java.io.ObjectOutputStream s) throws IOException { writeHashtable(s); } /** * 执行Hashtable到ObjectOutputStream的序列化。 * Properties类重写此方法。 */ void writeHashtable(java.io.ObjectOutputStream s) throws IOException { Entry<Object, Object> entryStack = null; synchronized (this) { // 写出threshold和loadFactor s.defaultWriteObject(); // 写出数组长度和元素数量 s.writeInt(table.length); s.writeInt(count); // 堆叠表中的条目副本 for (Entry<?, ?> entry : table) { while (entry != null) { entryStack = new Entry<>(0, entry.key, entry.value, entryStack); entry = entry.next; } } } // 从堆叠的条目中写出键/值对象 while (entryStack != null) { s.writeObject(entryStack.key); s.writeObject(entryStack.value); entryStack = entryStack.next; } } /** * 由Properties调用,写出模拟的threshold和loadfactor。 */ final void defaultWriteHashtable(java.io.ObjectOutputStream s, int length, float loadFactor) throws IOException { this.threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1); this.loadFactor = loadFactor; s.defaultWriteObject(); } /** * 从流中重构Hashtable(即反序列化它)。 */ @java.io.Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { readHashtable(s); } /** * 执行从ObjectInputStream反序列化Hashtable。 * Properties类重写此方法。 */ void readHashtable(ObjectInputStream s) throws IOException, ClassNotFoundException { ObjectInputStream.GetField fields = s.readFields(); // 读取并验证loadFactor(忽略threshold - 它将被重新计算) float lf = fields.get("loadFactor", 0.75f); if (lf <= 0 || Float.isNaN(lf)) throw new StreamCorruptedException("非法负载因子: " + lf); lf = Math.clamp(lf, 0.25f, 4.0f); // 读取数组的原始长度和元素数量 int origlength = s.readInt(); int elements = s.readInt(); // 验证元素数量 if (elements < 0) throw new StreamCorruptedException("非法元素数量: " + elements); // 限制原始长度为大于elements / loadFactor // (这是自动增长所强制执行的不变量) origlength = Math.max(origlength, (int)(elements / lf) + 1); // 计算新长度,留出5% + 3的增长空间,但 // 不大于限制的原始长度。如果长度足够大,使其为奇数, // 这有助于分布条目。防止长度最终为零,这是无效的。 int length = (int)(elements * 1.05f / lf) + 3; if (length > elements && (length & 1) == 0) length--; length = Math.min(length, origlength); if (length < 0) { // 溢出 length = origlength; } // 检查Map.Entry[].class,因为它是我们实际创建的类的最近公共类型。 SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length); Hashtable.UnsafeHolder.putLoadFactor(this, lf); table = new Entry<?,?>[length]; threshold = (int)Math.min(length * lf, MAX_ARRAY_SIZE + 1); count = 0; // 读取元素数量,然后读取所有键/值对象 for (; elements > 0; elements--) { @SuppressWarnings("unchecked") K key = (K)s.readObject(); @SuppressWarnings("unchecked") V value = (V)s.readObject(); // 为了性能消除同步 reconstitutionPut(table, key, value); } } // 反序列化期间重置final字段的支持 private static final class UnsafeHolder { private UnsafeHolder() { throw new InternalError(); } private static final jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); private static final long LF_OFFSET = unsafe.objectFieldOffset(Hashtable.class, "loadFactor"); static void putLoadFactor(Hashtable<?, ?> table, float lf) { unsafe.putFloat(table, LF_OFFSET, lf); } } /** * readObject使用的put方法。之所以提供此方法,是因为put * 是可覆盖的,并且不应该在readObject中调用,因为子类可能尚未初始化。 * * <p>这与常规put方法在几个方面不同。不需要检查rehashing,因为 * 表中初始的元素数量是已知的。不增加modCount,并且没有同步,因为我们正在创建新实例。 * 也不需要返回值。 */ private void reconstitutionPut(Entry<?,?>[] tab, K key, V value) throws StreamCorruptedException { if (value == null) { throw new java.io.StreamCorruptedException(); } // 确保键不在哈希表中。 // 这在反序列化版本中不应该发生。 int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index]; e != null; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { throw new java.io.StreamCorruptedException(); } } // 创建新条目 @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; } /** * Hashtable桶冲突列表条目 */ private static class Entry<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Entry<K,V> next; protected Entry(int hash, K key, V value, Entry<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } @SuppressWarnings("unchecked") protected Object clone() { return new Entry<>(hash, key, value, (next==null ? null : (Entry<K,V>) next.clone())); } // Map.Entry操作 public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { if (value == null) throw new NullPointerException(); V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry<?, ?> e)) return false; return (key==null ? e.getKey()==null : key.equals(e.getKey())) && (value==null ? e.getValue()==null : value.equals(e.getValue())); } public int hashCode() { return hash ^ Objects.hashCode(value); } public String toString() { return key.toString()+"="+value.toString(); } } // 枚举/迭代的类型 private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2; /** * 哈希表枚举器类。此类同时实现了 * Enumeration和Iterator接口,但可以创建单个实例 * 禁用Iterator方法。这是必要的,以避免无意中增加用户的能力 * 通过传递Enumeration授予。 */ private class Enumerator<T> implements Enumeration<T>, Iterator<T> { final Entry<?,?>[] table = Hashtable.this.table; int index = table.length; Entry<?,?> entry; Entry<?,?> lastReturned; final int type; /** * 指示此Enumerator是作为Iterator还是 * Enumeration服务。(true -> Iterator)。 */ final boolean iterator; /** * 迭代器认为后备Hashtable应该具有的modCount值。 * 如果此期望被违反,迭代器已检测到并发修改。 */ protected int expectedModCount = Hashtable.this.modCount; Enumerator(int type, boolean iterator) { this.type = type; this.iterator = iterator; } public boolean hasMoreElements() { Entry<?,?> e = entry; int i = index; Entry<?,?>[] t = table; /* 使用局部变量以加快循环迭代 */ while (e == null && i > 0) { e = t[--i]; } entry = e; index = i; return e != null; } @SuppressWarnings("unchecked") public T nextElement() { Entry<?,?> et = entry; int i = index; Entry<?,?>[] t = table; /* 使用局部变量以加快循环迭代 */ while (et == null && i > 0) { et = t[--i]; } entry = et; index = i; if (et != null) { Entry<?,?> e = lastReturned = entry; entry = e.next; return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e); } throw new NoSuchElementException("Hashtable Enumerator"); } // Iterator方法 public boolean hasNext() { return hasMoreElements(); } public T next() { if (Hashtable.this.modCount != expectedModCount) throw new ConcurrentModificationException(); return nextElement(); } public void remove() { if (!iterator) throw new UnsupportedOperationException(); if (lastReturned == null) throw new IllegalStateException("Hashtable Enumerator"); if (modCount != expectedModCount) throw new ConcurrentModificationException(); synchronized(Hashtable.this) { Entry<?,?>[] tab = Hashtable.this.table; int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { if (prev == null) tab[index] = e.next; else prev.next = e.next; expectedModCount++; lastReturned = null; Hashtable.this.modCount++; Hashtable.this.count--; return; } } throw new ConcurrentModificationException(); } } } }
TreeMap
lang包
object
/** * Object类是Java类层次结构的根类,所有类都直接或间接继承自此类。 * 以下是Object类的核心方法实现,展示了Java对象系统的底层机制 */ package java.lang_; import java.lang.*; /** * Class {@code Object} 是类层次结构的根类。每个类都以 {@code Object} 作为超类。 * 所有对象(包括数组)都实现了此类的方法。 * * @see java.lang.Class * @since 1.0 */ public class Object { // 对象头中的哈希码,由JVM在需要时计算,而非构造时立即生成 private transient int hash; /** * 构造一个新对象。 */ public Object() { // 实际JVM中,对象构造会分配内存并初始化对象头 } /** * 返回此对象的运行时类。返回的 {@code Class} 对象是由所表示类的 * {@code static synchronized} 方法锁定的对象。 * * @return 表示此对象运行时类的 {@code Class} 对象 */ public final native Class<?> getClass(); /** * 返回对象的哈希码值。此方法支持哈希表(如 {@link java.util.HashMap} 提供的哈希表)的操作。 * * @return 此对象的哈希码值 * @see java.lang.Object#equals(java.lang.Object) * @see java.util.HashMap */ public native int hashCode(); /** * 指示其他某个对象是否与此对象"相等"。 * <p>默认实现比较对象引用是否相等。 * * @param obj 要比较的引用对象。 * @return 如果此对象与 {@code obj} 参数相同,则返回 {@code true};否则返回 {@code false}。 */ public boolean equals(Object obj) { return (this == obj); } /** * 创建并返回此对象的一个副本。 * * @return 此对象的一个副本。 * @throws CloneNotSupportedException 如果对象的类不支持 {@code Cloneable} 接口,则抛出此异常。 * @see java.lang.Cloneable */ protected native Object clone() throws CloneNotSupportedException; /** * 返回该对象的字符串表示。 * <p>默认格式为 "类名@哈希码的十六进制表示"。 * * @return 该对象的字符串表示。 */ public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } /** * 唤醒在此对象监视器上等待的单个线程。 * * @throws IllegalMonitorStateException 如果当前线程不是此对象监视器的所有者。 * @see java.lang.Object#notifyAll() * @see java.lang.Object#wait() */ public final native void notify(); /** * 唤醒在此对象监视器上等待的所有线程。 * * @throws IllegalMonitorStateException 如果当前线程不是此对象监视器的所有者。 * @see java.lang.Object#notify() * @see java.lang.Object#wait() */ public final native void notifyAll(); /** * 导致当前线程等待,直到另一个线程调用此对象的 {@code notify()} 方法或 {@code notifyAll()} 方法。 * * @throws InterruptedException 如果当前线程在等待期间被中断。 * @throws IllegalMonitorStateException 如果当前线程不是此对象监视器的所有者。 */ public final native void wait() throws InterruptedException; /** * 导致当前线程等待,直到另一个线程调用此对象的 {@code notify()} 方法或 * {@code notifyAll()} 方法,或者指定的毫秒数已过。 * * @param timeout 等待的最长时间(毫秒) * @throws InterruptedException 如果当前线程在等待期间被中断。 * @throws IllegalMonitorStateException 如果当前线程不是此对象监视器的所有者。 * @throws IllegalArgumentException 如果 {@code timeout} 为负数。 */ public final void wait(long timeout) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout值不能为负数"); } if (timeout == 0) { wait(); return; } wait0(timeout); } /** * 导致当前线程等待,直到另一个线程调用此对象的 {@code notify()} 方法或 * {@code notifyAll()} 方法,或者指定的时间已过。 * * @param timeout 等待的最长时间(毫秒) * @param nanos 额外时间(纳秒),范围 0-999999 * @throws InterruptedException 如果当前线程在等待期间被中断。 * @throws IllegalMonitorStateException 如果当前线程不是此对象监视器的所有者。 * @throws IllegalArgumentException 如果 {@code timeout} 为负数或 {@code nanos} 不在合法范围内。 */ public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout值不能为负数"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException("nanos值必须在0-999999之间"); } if (nanos > 0 && timeout < Long.MAX_VALUE) { timeout++; } wait(timeout); } // 本地方法:JVM实现的wait基础功能 private final native void wait0(long timeoutMillis) throws InterruptedException; /** * 当垃圾回收器确定不存在对该对象的更多引用时,由垃圾回收器调用此方法。 * <p>此方法已被废弃,不建议重写。 * * @deprecated 已废弃,将在未来版本中移除。 * @throws Throwable 此方法抛出的任何异常 */ @Deprecated(since = "9", forRemoval = true) protected void finalize() throws Throwable { // 空实现,子类可重写但不推荐 } /** * 生成对象的哈希码(JVM内部实现) * 注意:真实JDK中hashCode的实现更为复杂,且可能不是直接存储 */ private native int internalGenerateHashCode(); }
system
### Java System 类核心逻辑解读 `java.lang.System` 类是Java中与系统交互的核心类,提供了标准输入输出、系统属性访问、本地方法调用等基础功能。以下从多个维度解析其实现逻辑。 ### 类的基本结构与初始化 #### 核心初始化流程 ```java private static native void registerNatives(); static { registerNatives(); } private System() { // 私有构造函数,防止实例化 } ``` - 通过静态代码块注册本地方法,底层由C/C++实现 - 私有构造函数确保该类无法被实例化,所有功能通过静态方法提供 #### 初始化阶段设计 ```java private static void initPhase1() { ... } private static int initPhase2(boolean printToStderr, boolean printStackTrace) { ... } private static void initPhase3() { ... } ``` - **三阶段初始化**: 1. **Phase1**:初始化系统属性、标准流、信号处理器 2. **Phase2**:初始化模块系统,创建引导模块层 3. **Phase3**:设置安全管理器、系统类加载器等高级功能 - 这种设计确保系统资源按依赖顺序加载,避免初始化冲突 ### 标准输入输出流实现 ```java public static final InputStream in = null; public static final PrintStream out = null; public static final PrintStream err = null; private static void setIn0(InputStream in) { ... } private static void setOut0(PrintStream out) { ... } private static void setErr0(PrintStream err) { ... } ``` #### 关键实现细节: 1. **延迟初始化**:初始值设为`null`,在`initPhase1()`中实际初始化 2. **装饰器模式**: - `In`类继承`FileInputStream`,重写`read`方法添加阻塞处理 - `Out`类继承`FileOutputStream`,重写`write`方法添加阻塞处理 3. **编码处理**: ```java private static PrintStream newPrintStream(OutputStream out, String enc) { if (enc != null) { return new PrintStream(..., Charset.forName(enc)); } return new PrintStream(...); } ``` - 根据`stdout.encoding`和`stderr.encoding`系统属性设置输出编码 ### 安全管理器机制 ```java @SuppressWarnings("removal") private static volatile SecurityManager security; public static void setSecurityManager(SecurityManager sm) { ... } public static SecurityManager getSecurityManager() { ... } ``` #### 安全控制逻辑: 1. **权限检查**: ```java private static void checkIO() { SecurityManager sm = getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("setIO")); } } ``` - 关键操作(如修改标准流)前进行权限验证 2. **安全策略配置**: - 通过`java.security.manager`系统属性控制安全管理器初始化 - 支持禁用安全管理器(`java.security.manager=disallow`) 3. **废弃处理**: ```java @Deprecated(since="17", forRemoval=true) public static void setSecurityManager(SecurityManager sm) { ... } ``` - 标记为废弃,未来版本可能移除 ### 系统时间与性能测量 ```java public static native long currentTimeMillis(); public static native long nanoTime(); ``` #### 时间实现特点: 1. **毫秒级时间**:`currentTimeMillis()`返回UTC 1970-01-01至今的毫秒数 2. **纳秒级时间**:`nanoTime()`返回高分辨率时间戳,用于测量时间间隔 3. **本地实现**:由JVM底层根据操作系统实现,例如: - Linux使用`gettimeofday()` - Windows使用`QueryPerformanceCounter()` ### 数组操作与哈希功能 ```java public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); public static native int identityHashCode(Object x); ``` #### 核心功能: 1. **高效数组复制**: - 本地方法实现,直接操作内存,比Java循环复制更高效 - 支持不同类型数组间的复制(需兼容类型) 2. **对象标识哈希码**: - `identityHashCode()`返回对象的原始哈希码,不受`hashCode()`重写影响 - 与`Object.hashCode()`的区别:即使对象重写了`hashCode()`,仍返回内存地址相关值 ### 系统属性与环境变量 ```java private static Properties props; public static Properties getProperties() { ... } public static String getProperty(String key) { ... } public static String setProperty(String key, String value) { ... } public static String getenv(String name) { ... } public static Map<String,String> getenv() { ... } ``` #### 实现要点: 1. **属性管理**: - 使用`Properties`对象存储系统属性 - 初始化时从VM获取默认属性(如`java.version`、`os.name`) 2. **环境变量访问**: - 通过`ProcessEnvironment`类封装不同操作系统的环境变量获取逻辑 - 支持安全检查:`checkPermission(new RuntimePermission("getenv."+name))` 3. **属性过滤**: ```java private static Properties createProperties(Map<String, String> initialProps) { // 过滤掉内部属性(如sun.nio.MaxDirectMemorySize) switch (prop) { case "sun.nio.MaxDirectMemorySize": break; default: properties.put(prop, entry.getValue()); } } ``` ### 日志功能实现 ```java public interface Logger { ... } public abstract static class LoggerFinder { ... } public static Logger getLogger(String name) { ... } ``` #### 日志系统设计: 1. **服务提供者接口(SPI)**: - 通过`LoggerFinder`查找日志实现,支持插件式日志框架 - 优先使用`ServiceLoader`加载自定义日志实现 2. **本地化日志**: ```java public Logger getLocalizedLogger(String name, ResourceBundle bundle, Module module) { return new LocalizedLoggerWrapper<>(getLogger(name, module), bundle); } ``` - 支持通过资源包实现日志消息本地化 3. **延迟加载**: - 使用`LazyLoggers`实现日志的延迟初始化,避免过早加载日志系统 ### 系统控制与资源回收 ```java public static void exit(int status) { ... } public static void gc() { ... } @Deprecated(since="18", forRemoval=true) public static void runFinalization() { ... } ``` #### 关键逻辑: 1. **系统退出**: - 调用`Runtime.getRuntime().exit(status)`,触发关机钩子 - 安全检查:`checkExit(status)` 2. **垃圾回收**: - `gc()`调用`Runtime.getRuntime().gc()`,建议JVM执行垃圾回收 - 非阻塞调用,不保证立即执行 3. **终结器处理**: - `runFinalization()`已废弃,建议使用`Cleaner`替代对象终结器 ### 本地库加载机制 ```java public static void load(String filename) { ... } public static void loadLibrary(String libname) { ... } public static native String mapLibraryName(String libname); ``` #### 加载流程: 1. **绝对路径加载**: - `load(String filename)`直接加载指定路径的本地库 2. **库名映射**: - `mapLibraryName(String libname)`根据操作系统映射库名: - Windows: `libname -> libname.dll` - Linux: `libname -> liblibname.so` 3. **安全检查**: - 调用`checkLink(libname)`验证加载权限 - 本地方法`load0()`由JVM实现实际加载逻辑 ### 核心设计模式与最佳实践 1. **单例思想**: - 通过私有构造函数确保类不可实例化,所有功能通过静态方法提供 2. **分层初始化**: - 三阶段初始化避免循环依赖,确保资源按顺序加载 3. **安全优先**: - 关键操作前进行安全检查,防止未授权访问 4. **兼容性设计**: - 保留已废弃功能(如`runFinalization`),逐步过渡到新机制 5. **性能优化**: - 本地方法实现关键操作(如`arraycopy`),提升执行效率 ### 与其他核心类的协作 1. **与Runtime类**: - `System.exit()`调用`Runtime.getRuntime().exit()` - `System.gc()`调用`Runtime.getRuntime().gc()` 2. **与ClassLoader类**: - 本地库加载时通过`ClassLoader.findNative()`查找本地方法 3. **与SecurityManager类**: - 所有敏感操作前调用安全管理器的权限检查方法 4. **与Thread类**: - 初始化阶段设置线程上下文类加载器、线程容器等 ### 总结 `System`类作为Java与操作系统交互的桥梁,通过分层初始化、本地方法调用、安全检查等机制,提供了系统级功能的统一接口。其设计体现了模块化、安全性和性能优化的最佳实践,是理解Java底层机制的重要入口。 实际使用中,应注意: - 避免修改标准输入输出流,除非必要 - 使用系统属性而非环境变量传递应用配置 - 优先使用`System.Logger`而非`System.out`进行日志输出 - 避免依赖已废弃的功能(如终结器)