自学java基础--泛型
一、集合框架整体结构
Collection(单列集合,存单个元素) │ ┌─────────────────┼─────────────────┐ │ │ │ List Set Queue (有序可重复) (无序不重复) (队列,先进先出) │ │ ┌────┼────┐ ┌────┼────┐ │ │ │ │ │ │ ArrayList LinkedList Vector HashSet LinkedHashSet TreeSet Map(双列集合,存键值对) │ ┌───────────┼───────────┐ │ │ │ HashMap LinkedHashMap TreeMap Hashtable Properties二、List:有序、可重复
1、 ArrayList(常用)
特点:基于数组实现,查询快,增删慢(中间位置)
// 创建 List<String> list = new ArrayList<>(); // 添加 list.add("苹果"); // 末尾添加 list.add("香蕉"); list.add(1, "橙子"); // 在索引1位置插入 // 获取 String first = list.get(0); // "苹果" // 修改 list.set(1, "葡萄"); // 把索引1的元素改成"葡萄" // 删除 list.remove(0); // 删除索引0的元素 list.remove("香蕉"); // 删除第一个"香蕉" // 遍历 for (String s : list) { System.out.println(s); } // 其他常用方法 list.size(); // 元素个数 list.isEmpty(); // 是否为空 list.contains("苹果"); // 是否包含 list.indexOf("苹果"); // 第一次出现的索引 list.clear(); // 清空ArrayList扩容过程:
初始:容量 10,存了 10 个元素 [a, b, c, d, e, f, g, h, i, j] 添加第 11 个元素时: 1. 创建新数组,容量 = 10 + 5 = 15 2. 把旧数组元素复制到新数组 3. 添加新元素 结果:[a, b, c, d, e, f, g, h, i, j, k, null, null, null, null]注意:频繁增删的场景不要用 ArrayList,因为中间插入/删除需要移动大量元素。
2、LinkedList
特点:基于双向链表实现,增删快、查询慢
List<String> list = new LinkedList<>(); // 用法和 ArrayList 一样,但多了一些链表特有的方法 LinkedList<String> linkedList = new LinkedList<>(); linkedList.addFirst("头部"); // 头部添加 linkedList.addLast("尾部"); // 尾部添加 linkedList.getFirst(); // 获取头部 linkedList.getLast(); // 获取尾部 linkedList.removeFirst(); // 移除头部 linkedList.removeLast(); // 移除尾部链表结构:
内存中的真实情况: ┌─────────────┐ ┌─────────────┐ │ 节点1 │ │ 节点2 │ │ 地址: 0x100 │ │ 地址: 0x200 │ │ │ │ │ │ prev: null │ │ prev: ─────┼───► 0x100(节点1的地址) │ item: "A" │ │ item: "B" │ │ next: ─────┼────► │ next: null │ │ 0x200 │ │ │ └─────────────┘ └─────────────┘ │ ▲ │ │ └──────────────────────┘ 节点1.next = 0x200(节点2的地址) 节点2.prev = 0x100(节点1的地址)插入元素:
原来: 节点1 ↔ 节点2 步骤1: 新节点.prev = 节点1 步骤2: 新节点.next = 节点2 步骤3: 节点1.next = 新节点 步骤4: 节点2.prev = 新节点 结果: 节点1 ↔ 新节点 ↔ 节点2只需要修改 4 个指针引用,不需要移动其他元素,所以增删快。
三、Set:无序、不重复
1、HashSet(常用)
特点:基于HashMap实现,不保证顺序
Set<String> set = new HashSet<>(); set.add("苹果"); set.add("香蕉"); set.add("苹果"); // ❌ 重复,不会添加,返回 false System.out.println(set); // [香蕉, 苹果] 或 [苹果, 香蕉](无序) // 判断是否存在 set.contains("苹果"); // true // 其他方法 set.size(); set.isEmpty(); set.remove("苹果"); set.clear();去重原理:
添加元素时: 1. 调用元素的 hashCode() 计算哈希值 2. 根据哈希值找到数组位置 3. 如果该位置为空 → 直接放入 4. 如果该位置有元素 → 调用 equals() 比较 - equals 返回 true → 重复,不添加 - equals 返回 false → 不重复,以链表/红黑树形式存放2、LinkedHashSet
特点:HashSet的子类,保持插入顺序
Set<String> set = new LinkedHashSet<>(); set.add("c"); set.add("a"); set.add("b"); System.out.println(set); // [c, a, b] 保持插入顺序3、TreeSet
特点:基于红黑树,自动排序
Set<Integer> set = new TreeSet<>(); set.add(3); set.add(1); set.add(2); System.out.println(set); // [1, 2, 3] 自动升序 // 自定义排序规则 Set<String> set2 = new TreeSet<>((a, b) -> b.compareTo(a)); // 降序 set2.add("b"); set2.add("a"); set2.add("c"); System.out.println(set2); // [c, b, a]四、Map:键值对
1、HashMap(常用)
Map<String, Integer> map = new HashMap<>(); // 添加/修改 map.put("张三", 20); // 添加 map.put("张三", 21); // key已存在,覆盖value // 获取 Integer age = map.get("张三"); // 21 Integer age2 = map.get("李四"); // null(不存在) // 安全获取(Java 8+) Integer age3 = map.getOrDefault("李四", 0); // 不存在返回 0 // 判断 map.containsKey("张三"); // true map.containsValue(20); // false(被覆盖成21了) // 删除 map.remove("张三"); // 遍历(多种方式) // 方式1:遍历键 for (String key : map.keySet()) { System.out.println(key + "=" + map.get(key)); } // 方式2:遍历键值对(推荐) for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } // 方式3:Java 8 Lambda map.forEach((k, v) -> System.out.println(k + "=" + v));2、LinkedHashMap
特点:保持插入顺序或访问顺序
// 保持插入顺序 Map<String, Integer> map = new LinkedHashMap<>(); map.put("a", 1); map.put("b", 2); map.put("c", 3); System.out.println(map); // {a=1, b=2, c=3} // 保持访问顺序(LRU 缓存用) Map<String, Integer> lruMap = new LinkedHashMap<>(16, 0.75f, true); lruMap.put("a", 1); lruMap.put("b", 2); lruMap.put("c", 3); lruMap.get("a"); // 访问 a System.out.println(lruMap); // {b=2, c=3, a=1} a移到最后3、TreeMap
特点:基于红黑树,按键排序
Map<String, Integer> map = new TreeMap<>(); map.put("c", 3); map.put("a", 1); map.put("b", 2); System.out.println(map); // {a=1, b=2, c=3} 按键升序总结:
需要存什么? │ ├── 单个元素,允许重复,有索引 → List │ ├── 查询多,随机访问 → ArrayList │ └── 频繁增删 → LinkedList │ ├── 单个元素,不重复 → Set │ ├── 不关心顺序 → HashSet │ ├── 保持插入顺序 → LinkedHashSet │ └── 需要排序 → TreeSet │ ├── 键值对 → Map │ ├── 不关心顺序 → HashMap │ ├── 保持插入顺序 → LinkedHashMap │ └── 按键排序 → TreeMap │ └── 先进先出 → Queue/Deque └── LinkedList 或 ArrayDeque