Java数组与集合详解
Java数组与集合详解
什么是数组?
数组是一种容器,可以存储固定大小的相同类型元素。在Java中,数组是引用类型。
数组的声明与初始化
一维数组
声明方式:
type[] arrayName;type arrayName[];初始化方式:
- 静态初始化:
int[] numbers = {1, 2, 3, 4, 5};String[] names = {"张三", "李四", "王五"};- 动态初始化:
int[] numbers = new int[5];String[] names = new String[3];二维数组
声明方式:
type[][] arrayName;type arrayName[][];初始化方式:
- 静态初始化:
int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}};- 动态初始化:
int[][] matrix = new int[3][3];数组的访问与操作
访问数组元素
使用索引访问数组元素,索引从0开始:
int[] numbers = {1, 2, 3, 4, 5};int first = numbers[0]; // 访问第一个元素int last = numbers[numbers.length - 1]; // 访问最后一个元素遍历数组
- 使用for循环:
int[] numbers = {1, 2, 3, 4, 5};for (int i = 0; i < numbers.length; i++) { System.out.println(numbers[i]);}- 使用增强型for循环:
int[] numbers = {1, 2, 3, 4, 5};for (int number : numbers) { System.out.println(number);}数组的长度
使用length属性获取数组的长度:
int[] numbers = {1, 2, 3, 4, 5};int length = numbers.length; // 5数组的局限性
- 固定大小:数组一旦创建,大小就不能改变
- 类型单一:数组只能存储相同类型的元素
- 缺少内置方法:数组没有提供添加、删除等操作的内置方法
- 需要手动扩容:当需要存储更多元素时,需要手动创建新数组并复制元素
集合框架
为了克服数组的局限性,Java提供了集合框架。集合框架是一组用于存储和操作对象的接口和类。
集合框架的层次结构
Java集合框架主要包含以下接口:
- Collection:所有集合的根接口
- List:有序集合,允许重复元素
- Set:无序集合,不允许重复元素
- Queue:队列,先进先出
- Map:键值对映射,不直接继承自Collection
常用集合类
List接口的实现类
- ArrayList:基于动态数组实现,查询快,增删慢
- LinkedList:基于双向链表实现,查询慢,增删快
- Vector:线程安全的ArrayList,效率较低
Set接口的实现类
- HashSet:基于哈希表实现,无序,不允许重复元素
- LinkedHashSet:基于哈希表和链表实现,有序(插入顺序),不允许重复元素
- TreeSet:基于红黑树实现,有序(自然顺序或比较器顺序),不允许重复元素
Map接口的实现类
- HashMap:基于哈希表实现,无序,键不允许重复
- LinkedHashMap:基于哈希表和链表实现,有序(插入顺序),键不允许重复
- TreeMap:基于红黑树实现,有序(自然顺序或比较器顺序),键不允许重复
- Hashtable:线程安全的HashMap,效率较低
List集合
ArrayList
创建ArrayList:
List<String> names = new ArrayList<>();List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));常用方法:
add(E element):添加元素add(int index, E element):在指定位置添加元素get(int index):获取指定位置的元素set(int index, E element):替换指定位置的元素remove(int index):删除指定位置的元素remove(Object o):删除指定元素size():获取集合大小contains(Object o):判断集合是否包含指定元素clear():清空集合isEmpty():判断集合是否为空toArray():将集合转换为数组
示例:
List<String> names = new ArrayList<>();names.add("张三");names.add("李四");names.add("王五");System.out.println(names.get(0)); // 张三names.remove(1); // 删除李四System.out.println(names.size()); // 2Set集合
HashSet
创建HashSet:
Set<String> names = new HashSet<>();Set<Integer> numbers = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));常用方法:
add(E e):添加元素remove(Object o):删除元素size():获取集合大小contains(Object o):判断集合是否包含指定元素clear():清空集合isEmpty():判断集合是否为空
示例:
Set<String> names = new HashSet<>();names.add("张三");names.add("李四");names.add("张三"); // 重复元素,不会添加System.out.println(names.size()); // 2Map集合
HashMap
创建HashMap:
Map<String, Integer> scores = new HashMap<>();常用方法:
put(K key, V value):添加键值对get(Object key):根据键获取值remove(Object key):根据键删除键值对size():获取键值对数量containsKey(Object key):判断是否包含指定键containsValue(Object value):判断是否包含指定值clear():清空MapisEmpty():判断Map是否为空keySet():获取所有键的集合values():获取所有值的集合entrySet():获取所有键值对的集合
示例:
Map<String, Integer> scores = new HashMap<>();scores.put("张三", 95);scores.put("李四", 88);scores.put("王五", 92);System.out.println(scores.get("张三")); // 95scores.remove("李四");System.out.println(scores.size()); // 2
// 遍历Mapfor (String name : scores.keySet()) { System.out.println(name + ": " + scores.get(name));}
for (Map.Entry<String, Integer> entry : scores.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue());}集合的遍历
遍历List
- 使用for循环:
List<String> names = new ArrayList<>();names.add("张三");names.add("李四");names.add("王五");
for (int i = 0; i < names.size(); i++) { System.out.println(names.get(i));}- 使用增强型for循环:
for (String name : names) { System.out.println(name);}- 使用迭代器:
Iterator<String> iterator = names.iterator();while (iterator.hasNext()) { System.out.println(iterator.next());}遍历Set
- 使用增强型for循环:
Set<String> names = new HashSet<>();names.add("张三");names.add("李四");names.add("王五");
for (String name : names) { System.out.println(name);}- 使用迭代器:
Iterator<String> iterator = names.iterator();while (iterator.hasNext()) { System.out.println(iterator.next());}遍历Map
- 遍历键:
Map<String, Integer> scores = new HashMap<>();scores.put("张三", 95);scores.put("李四", 88);scores.put("王五", 92);
for (String name : scores.keySet()) { System.out.println(name + ": " + scores.get(name));}- 遍历键值对:
for (Map.Entry<String, Integer> entry : scores.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue());}- 遍历值:
for (Integer score : scores.values()) { System.out.println(score);}数组与集合的转换
数组转集合
int[] numbers = {1, 2, 3, 4, 5};List<Integer> list = Arrays.stream(numbers).boxed().collect(Collectors.toList());
String[] names = {"张三", "李四", "王五"};List<String> nameList = Arrays.asList(names);Set<String> nameSet = new HashSet<>(Arrays.asList(names));集合转数组
List<String> names = new ArrayList<>();names.add("张三");names.add("李四");names.add("王五");
// 方法1:使用toArray()Object[] objects = names.toArray();
// 方法2:使用toArray(T[] a)String[] nameArray = names.toArray(new String[0]);最佳实践
-
选择合适的集合:
- 需要有序、可重复的元素时,使用List
- 需要无序、不可重复的元素时,使用Set
- 需要键值对映射时,使用Map
-
根据操作选择具体实现:
- 查询操作多时,使用ArrayList
- 增删操作多时,使用LinkedList
- 需要排序时,使用TreeSet或TreeMap
- 需要保持插入顺序时,使用LinkedHashSet或LinkedHashMap
-
使用泛型:使用泛型可以避免类型转换错误,提高代码安全性。
-
初始化时指定容量:对于已知大小的集合,初始化时指定容量可以提高性能。
-
使用增强型for循环:遍历集合时,优先使用增强型for循环,代码更简洁。
-
注意空指针异常:在使用集合前,检查集合是否为null。
-
使用Collections工具类:Collections工具类提供了许多有用的方法,如排序、查找、反转等。
常见陷阱
-
Arrays.asList()的局限性:Arrays.asList()返回的是一个固定大小的列表,不支持添加和删除操作。
-
集合与原始类型:集合只能存储对象,不能存储原始类型,需要使用包装类。
-
ConcurrentModificationException:在迭代过程中修改集合,会抛出ConcurrentModificationException异常。
-
HashMap的键:HashMap的键应该是不可变的,否则可能导致键找不到。
-
HashSet的元素:HashSet的元素应该正确实现equals()和hashCode()方法,否则可能导致重复元素。
总结
数组和集合是Java中存储数据的重要容器,它们各有优缺点。数组适合存储固定大小的相同类型元素,而集合适合存储动态大小的对象。在实际开发中,我们应该根据具体需求选择合适的容器。
本文介绍了Java的数组和常用集合类,包括它们的创建、初始化、访问和操作方法。希望本文能够帮助你更好地理解Java的数组和集合,为后续的学习打下坚实的基础。
练习
-
编写一个程序,使用ArrayList存储学生信息,并实现添加、删除、修改和查询操作。
-
编写一个程序,使用HashSet存储不重复的整数,并实现添加、删除和遍历操作。
-
编写一个程序,使用HashMap存储学生的姓名和成绩,并实现添加、删除、修改和查询操作。
-
编写一个程序,将数组转换为集合,然后再将集合转换回数组。
-
编写一个程序,使用Collections工具类对List进行排序、查找和反转操作。
通过这些练习,你将更加熟悉Java的数组和集合,为后续的学习做好准备。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!