
1. Java泛型与集合类概述在Java开发中泛型Generics和集合类Collections是两个密不可分的重要概念。泛型提供了编译时类型安全检查机制而集合类则是存储和操作对象组的基础框架。这两者的结合使用使得Java程序员能够以类型安全的方式处理各种数据结构。泛型最早在Java 5中引入它允许我们在定义类、接口和方法时使用类型参数。这种参数化的类型在编译时会被具体的类型所替代从而避免了运行时的类型转换错误。例如我们可以声明一个ListString明确表示这个列表只能包含字符串对象。集合类则是Java标准库中用于存储和操作对象组的框架。Java集合框架主要包括以下几种核心接口Collection集合层次结构的根接口List有序集合元素可重复Set不包含重复元素的集合Map键值对映射Queue队列实现提示Java集合框架的设计遵循了接口与实现分离的原则例如List是一个接口而ArrayList和LinkedList是它的具体实现类。2. 泛型的核心概念与使用2.1 泛型的基本语法泛型的基本语法非常简单通过在类名或接口名后面添加尖括号来声明类型参数。例如public class BoxT { private T content; public void setContent(T content) { this.content content; } public T getContent() { return content; } }在这个例子中T是类型参数它可以是任何非基本数据类型。当我们实例化这个类时可以指定具体的类型BoxString stringBox new Box(); stringBox.setContent(Hello); String content stringBox.getContent(); // 不需要类型转换2.2 泛型方法的定义除了泛型类我们还可以定义泛型方法。泛型方法可以在普通类中定义也可以在泛型类中定义。语法如下public T void printArray(T[] array) { for (T element : array) { System.out.println(element); } }调用泛型方法时通常不需要显式指定类型参数编译器可以根据上下文推断出正确的类型Integer[] intArray {1, 2, 3}; printArray(intArray); // 自动推断T为Integer2.3 泛型的类型擦除Java的泛型是通过类型擦除Type Erasure实现的这意味着泛型类型信息只在编译时存在在运行时会被擦除。例如ListString和ListInteger在运行时都会变成List。这种设计带来了一些限制不能创建泛型数组new T[size]是不允许的不能使用instanceof检查泛型类型不能抛出或捕获泛型类的实例注意由于类型擦除重载方法时如果只是类型参数不同会导致编译错误。例如void method(ListString list)和void method(ListInteger list)不能同时存在。3. Java集合框架详解3.1 List接口及其实现List是有序集合允许重复元素。Java中常用的List实现有ArrayList基于动态数组实现随机访问快插入删除慢LinkedList基于双向链表实现插入删除快随机访问慢Vector线程安全的ArrayList性能较差使用示例ListString arrayList new ArrayList(); arrayList.add(Java); arrayList.add(Python); arrayList.add(1, C); // 在索引1处插入 ListString linkedList new LinkedList(); linkedList.addAll(arrayList); // 添加所有元素3.2 Set接口及其实现Set是不允许重复元素的集合。常用实现有HashSet基于哈希表实现无序LinkedHashSet保持插入顺序的HashSetTreeSet基于红黑树实现有序使用示例SetInteger hashSet new HashSet(); hashSet.add(1); hashSet.add(2); hashSet.add(1); // 重复元素不会被添加 SetString treeSet new TreeSet(); treeSet.add(Banana); treeSet.add(Apple); treeSet.add(Orange); // 元素会按字母顺序排序3.3 Map接口及其实现Map存储键值对映射。常用实现有HashMap基于哈希表实现无序LinkedHashMap保持插入顺序的HashMapTreeMap基于红黑树实现按键排序Hashtable线程安全的HashMap已过时使用示例MapString, Integer hashMap new HashMap(); hashMap.put(Alice, 25); hashMap.put(Bob, 30); hashMap.put(Charlie, 28); MapString, Integer treeMap new TreeMap(hashMap); // 按键名字母顺序排序4. 泛型与集合类的结合使用4.1 类型安全的集合泛型的主要优势之一就是可以创建类型安全的集合。在没有泛型的时代我们需要这样写代码List list new ArrayList(); list.add(Hello); String s (String) list.get(0); // 需要显式类型转换使用泛型后ListString list new ArrayList(); list.add(Hello); String s list.get(0); // 自动类型转换这不仅减少了代码量更重要的是在编译时就能发现类型不匹配的错误。4.2 通配符与边界Java泛型提供了通配符?来表示未知类型以及边界来限制类型参数的范围无界通配符List?表示元素类型未知的List上界通配符List? extends Number表示元素是Number或其子类下界通配符List? super Integer表示元素是Integer或其父类使用示例public static double sum(List? extends Number list) { double sum 0; for (Number n : list) { sum n.doubleValue(); } return sum; }这个方法可以接受ListInteger、ListDouble等参数。4.3 泛型与集合工具类Java提供了Collections工具类包含各种操作集合的静态方法。结合泛型这些方法变得更加安全和强大ListInteger numbers Arrays.asList(3, 1, 4, 1, 5, 9); Collections.sort(numbers); // 排序 Collections.reverse(numbers); // 反转 Collections.shuffle(numbers); // 随机打乱5. Stream API与集合操作5.1 Stream简介Java 8引入的Stream API提供了一种声明式处理集合数据的方式。Stream不是数据结构而是对数据源如集合进行高效聚合操作的工具。Stream的主要特点不存储数据只是从数据源如集合获取数据不修改源数据操作会产生新Stream惰性执行中间操作不会立即执行可消费性Stream只能被消费一次5.2 创建Stream有多种方式可以创建Stream// 从集合创建 ListString list Arrays.asList(a, b, c); StreamString stream1 list.stream(); // 从数组创建 String[] array {a, b, c}; StreamString stream2 Arrays.stream(array); // 直接创建 StreamString stream3 Stream.of(a, b, c); // 创建无限流 StreamInteger stream4 Stream.iterate(0, n - n 2);5.3 常用Stream操作Stream操作分为中间操作和终端操作中间操作返回Stream可以链式调用filter过滤元素map转换元素sorted排序distinct去重limit限制数量skip跳过元素终端操作产生结果或副作用forEach遍历元素collect收集结果reduce归约操作count计数anyMatch/allMatch/noneMatch匹配检查使用示例ListString names Arrays.asList(Alice, Bob, Charlie, David); // 过滤长度大于3的名字转换为大写排序收集到List ListString result names.stream() .filter(name - name.length() 3) .map(String::toUpperCase) .sorted() .collect(Collectors.toList());5.4 并行StreamStream API支持并行处理可以充分利用多核处理器的优势long count names.parallelStream() .filter(name - name.length() 3) .count();注意并行Stream不一定总是更快对于小数据集或存在共享状态的情况串行Stream可能更高效。6. 泛型与集合的最佳实践6.1 选择合适的集合类型根据需求选择合适的集合类型可以显著提高性能需要快速随机访问ArrayList频繁插入删除LinkedList需要去重HashSet需要保持插入顺序LinkedHashSet需要排序TreeSet键值对存储HashMap或TreeMap6.2 避免原始类型尽量使用泛型集合避免使用原始类型raw type// 不好的做法 List list new ArrayList(); // 好的做法 ListString list new ArrayList();6.3 使用不可变集合当集合不需要修改时考虑使用不可变集合ListString immutableList Collections.unmodifiableList(list); SetString immutableSet Collections.unmodifiableSet(set); MapString, Integer immutableMap Collections.unmodifiableMap(map);Java 9还引入了更方便的工厂方法ListString list List.of(a, b, c); SetString set Set.of(a, b, c); MapString, Integer map Map.of(a, 1, b, 2);6.4 注意集合的线程安全性大多数集合实现不是线程安全的。在多线程环境中可以考虑使用同步包装器ListString syncList Collections.synchronizedList(list);使用并发集合ConcurrentMapString, Integer map new ConcurrentHashMap(); CopyOnWriteArrayListString list new CopyOnWriteArrayList();使用不可变集合6.5 有效使用Stream API使用Stream API时注意以下几点避免在Stream操作中修改源集合复杂的操作可以分解为多个Stream操作对于简单操作传统循环可能更高效注意中间操作的顺序对性能的影响考虑使用并行Stream处理大数据集7. 常见问题与解决方案7.1 泛型数组创建问题由于类型擦除不能直接创建泛型数组// 编译错误 T[] array new T[size];解决方案使用SuppressWarnings(unchecked)和强制类型转换SuppressWarnings(unchecked) T[] array (T[]) new Object[size];使用反射需要Class对象T[] array (T[]) Array.newInstance(clazz, size);7.2 集合与数组转换集合与数组之间的转换是常见操作// 集合转数组 ListString list Arrays.asList(a, b, c); String[] array1 list.toArray(new String[0]); // 数组转集合 String[] array2 {a, b, c}; ListString list2 new ArrayList(Arrays.asList(array2));注意Arrays.asList()返回的是固定大小的列表不能添加或删除元素。7.3 集合的深拷贝与浅拷贝集合的拷贝分为浅拷贝和深拷贝浅拷贝只复制引用不复制对象ListString newList new ArrayList(oldList);深拷贝复制对象本身ListPerson newList oldList.stream() .map(p - new Person(p.getName())) // 假设Person有拷贝构造函数 .collect(Collectors.toList());7.4 集合的性能优化提高集合性能的几个技巧为集合指定初始容量减少扩容开销ListString list new ArrayList(1000); MapString, Integer map new HashMap(1000);对于频繁查询的Map调整负载因子MapString, Integer map new HashMap(1000, 0.75f);使用String.intern()作为Map的键减少内存使用考虑使用原始类型特化集合如Eclipse Collections、FastUtil7.5 处理并发修改异常ConcurrentModificationException是使用集合时常见的异常通常发生在遍历集合时修改集合解决方案使用迭代器的remove方法IteratorString it list.iterator(); while (it.hasNext()) { String s it.next(); if (s.equals(remove)) { it.remove(); // 安全删除 } }使用并发集合先收集要删除的元素最后统一删除使用Stream的filter操作8. 实际应用案例8.1 使用泛型实现缓存系统public class CacheK, V { private final MapK, V map new HashMap(); private final int maxSize; public Cache(int maxSize) { this.maxSize maxSize; } public void put(K key, V value) { if (map.size() maxSize) { // 简单的LRU策略移除第一个元素 IteratorK it map.keySet().iterator(); if (it.hasNext()) { map.remove(it.next()); } } map.put(key, value); } public V get(K key) { return map.get(key); } }8.2 使用Stream处理复杂数据public class Employee { private String name; private int age; private double salary; private Department department; // 构造方法、getter和setter省略 } public class Department { private String name; private String location; // 构造方法、getter和setter省略 } // 示例统计各部门的平均工资 MapString, Double avgSalaryByDept employees.stream() .collect(Collectors.groupingBy( e - e.getDepartment().getName(), Collectors.averagingDouble(Employee::getSalary) ));8.3 自定义泛型比较器public class GenericComparatorT extends ComparableT implements ComparatorT { private final boolean ascending; public GenericComparator(boolean ascending) { this.ascending ascending; } Override public int compare(T o1, T o2) { int result o1.compareTo(o2); return ascending ? result : -result; } } // 使用示例 ListInteger numbers Arrays.asList(3, 1, 4, 1, 5, 9); numbers.sort(new GenericComparator(false)); // 降序排序8.4 类型安全的工厂模式public interface FactoryT { T create(); } public class StringFactory implements FactoryString { Override public String create() { return Hello; } } public class IntegerFactory implements FactoryInteger { Override public Integer create() { return 42; } } // 使用示例 FactoryString stringFactory new StringFactory(); String s stringFactory.create(); FactoryInteger intFactory new IntegerFactory(); Integer i intFactory.create();9. 高级主题与未来方向9.1 Java泛型的局限性尽管Java泛型非常强大但仍有一些局限性不能使用基本类型作为类型参数可以使用包装类不能创建泛型数组类型擦除导致运行时类型信息丢失不能直接实例化类型参数需要反射9.2 与其他语言泛型的比较C#泛型使用具体化reification运行时保留类型信息C模板编译时多态更灵活但更复杂Scala泛型更丰富的特性如高阶类型、型变注解9.3 Java集合框架的演进Java集合框架在不断演进Java 5引入泛型Java 7钻石操作符简化泛型实例化Java 8引入Stream API和Lambda表达式Java 9引入不可变集合的工厂方法Java 10引入var局部变量类型推断9.4 第三方集合库除了标准库还有一些优秀的第三方集合库GuavaGoogle的Java工具库提供更多集合类型和实用方法Eclipse Collections高性能集合框架FastUtil原始类型特化的集合Trove针对原始类型优化的集合9.5 响应式编程与集合响应式编程如Reactor、RxJava提供了处理异步数据流的新方式FluxString flux Flux.fromIterable(list) .filter(s - s.length() 3) .map(String::toUpperCase);这种模式特别适合处理大量数据或异步事件流。