java进阶(中)
集合
-
集合的特点
- 可以动态保存任意多个对象,使用比较方便
- 提供了一系列方便的操作对象的方法:add、remove、set、get
-
java集合类很多,主要分为两大类,如图
![](https://pic1.imgdb.cn/item/67a5d732d0e0a243d4fc9007.jpg)
LInk(接口)
ArrayList(Link实现类)
ArrayList
是 Java 中最常用的集合类之一,它实现了List
接口,基于动态数组实现,允许动态地添加和删除元素。以下是ArrayList
的常用方法及其使用示例:
1. 构造方法
ArrayList
提供了多种构造方法,用于创建不同类型的实例:
-
无参构造方法:创建一个空的
ArrayList
,默认初始容量为10。ArrayList<String> list1 = new ArrayList<>();
-
指定初始容量的构造方法:创建一个具有指定初始容量的空
ArrayList
。ArrayList<String> list2 = new ArrayList<>(100);
-
从其他集合构造:创建一个包含指定集合元素的
ArrayList
。ArrayList<String> list3 = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
2. 添加元素
ArrayList
提供了多种方法用于添加元素:
-
add(E e)
:在列表末尾添加一个元素。list1.add("Apple"); list1.add("Banana");
-
add(int index, E e)
:在指定位置插入一个元素。list1.add(1, "Orange"); // 在索引1的位置插入"Orange"
3. 删除元素
ArrayList
提供了多种方法用于删除元素:
-
remove(int index)
:删除指定索引位置的元素,并返回被删除的元素。String removedElement = list1.remove(1); // 删除索引为1的元素 System.out.println("Removed element: " + removedElement);
-
remove(Object o)
:删除第一个匹配的元素。list1.remove("Banana"); // 删除第一个"Banana"
4. 访问元素
ArrayList
提供了多种方法用于访问元素:
-
get(int index)
:获取指定索引位置的元素。String element = list1.get(0); // 获取索引为0的元素 System.out.println("Element at index 0: " + element);
-
indexOf(Object o)
:返回指定元素第一次出现的索引,如果不存在则返回-1。int index = list1.indexOf("Apple"); System.out.println("Index of 'Apple': " + index);
-
lastIndexOf(Object o)
:返回指定元素最后一次出现的索引,如果不存在则返回-1。int lastIndex = list1.lastIndexOf("Apple"); System.out.println("Last index of 'Apple': " + lastIndex);
5. 更新元素
ArrayList
提供了方法用于更新指定位置的元素:
-
set(int index, E e)
:替换指定索引位置的元素,并返回被替换的元素。String oldElement = list1.set(0, "Grape"); // 将索引为0的元素替换为"Grape" System.out.println("Old element: " + oldElement);
6. 遍历元素
ArrayList
可以通过多种方式遍历:
-
for-each
循环:for (String fruit : list1) {System.out.println(fruit); }
-
for
循环:for (int i = 0; i < list1.size(); i++) {System.out.println(list1.get(i)); }
-
Iterator
:Iterator<String> iterator = list1.iterator(); while (iterator.hasNext()) {System.out.println(iterator.next()); }
-
Stream
API(Java 8及以上):list1.stream().forEach(System.out::println);
7. 其他常用方法
-
size()
:返回列表中的元素数量。int size = list1.size(); System.out.println("Size of list: " + size);
-
isEmpty()
:判断列表是否为空。boolean isEmpty = list1.isEmpty(); System.out.println("Is list empty? " + isEmpty);
-
clear()
:清空列表中的所有元素。list1.clear(); System.out.println("List after clearing: " + list1);
-
contains(Object o)
:判断列表是否包含指定元素。boolean contains = list1.contains("Apple"); System.out.println("Does list contain 'Apple'? " + contains);
-
toArray()
:将列表转换为数组。Object[] array = list1.toArray(); System.out.println("Array: " + Arrays.toString(array));
-
subList(int fromIndex, int toIndex)
:返回列表的一个子列表,范围为fromIndex
到toIndex-1
。List<String> sublist = list1.subList(1, 3); System.out.println("Sublist: " + sublist);
LinkedList (Link实现类)
LinkedList
是 Java 中的一个非常重要的集合类,它实现了 List
接口和 Deque
接口(双端队列)。LinkedList
基于双向链表实现,具有以下特点和用途:
1. 特点
- 基于双向链表:每个元素都包含一个指向下一个元素的引用和一个指向前一个元素的引用。这种结构使得插入和删除操作非常高效,时间复杂度为 O(1)。
- 动态大小:
LinkedList
的大小是动态的,可以根据需要自动扩展。 - 支持多种操作:除了
List
接口提供的方法外,LinkedList
还提供了额外的方法来支持队列和双端队列的操作。
2. 常用方法
以下是 LinkedList
的一些常用方法,按功能分类:
2.1 添加元素
-
add(E e)
:将元素添加到链表的末尾。LinkedList<String> list = new LinkedList<>(); list.add("Apple"); list.add("Banana");
-
addFirst(E e)
:将元素添加到链表的头部。list.addFirst("Orange");
-
addLast(E e)
:将元素添加到链表的尾部(等同于add(E e)
)。list.addLast("Cherry");
-
add(int index, E e)
:在指定位置插入元素。list.add(1, "Grape");
2.2 删除元素
-
remove()
:删除链表头部的元素,并返回被删除的元素。String removed = list.remove();
-
removeLast()
:删除链表尾部的元素,并返回被删除的元素。String removedLast = list.removeLast();
-
remove(Object o)
:删除第一个匹配的元素。list.remove("Banana");
-
remove(int index)
:删除指定索引位置的元素,并返回被删除的元素。String removedAtIndex = list.remove(1);
2.3 访问元素
-
get(int index)
:获取指定索引位置的元素。String element = list.get(1);
-
getFirst()
:获取链表头部的元素,但不删除。String first = list.getFirst();
-
getLast()
:获取链表尾部的元素,但不删除。String last = list.getLast();
2.4 队列操作
-
poll()
:获取并删除链表头部的元素。如果链表为空,则返回null
。String polled = list.poll();
-
pollLast()
:获取并删除链表尾部的元素。如果链表为空,则返回null
。String polledLast = list.pollLast();
-
offer(E e)
:将元素添加到链表尾部,等同于add(E e)
。list.offer("Mango");
-
offerFirst(E e)
:将元素添加到链表头部。list.offerFirst("Kiwi");
-
offerLast(E e)
:将元素添加到链表尾部(等同于offer(E e)
)。list.offerLast("Peach");
2.5 其他方法
-
size()
:返回链表中的元素数量。int size = list.size();
-
isEmpty()
:判断链表是否为空。boolean isEmpty = list.isEmpty();
-
clear()
:清空链表中的所有元素。list.clear();
-
contains(Object o)
:判断链表是否包含指定元素。boolean contains = list.contains("Apple");
3. 遍历 LinkedList
LinkedList
可以通过多种方式遍历:
3.1 使用 for-each
循环
for (String fruit : list) {System.out.println(fruit);
}
3.2 使用 Iterator
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {System.out.println(iterator.next());
}
3.3 使用 ListIterator
ListIterator
支持双向遍历,并且可以在遍历过程中插入、删除和替换元素。
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {System.out.println(listIterator.next());
}
3.4 使用 Stream
API(Java 8及以上)
list.stream().forEach(System.out::println);
4. 使用场景
- 频繁插入和删除:
LinkedList
的插入和删除操作非常高效,适用于需要频繁进行这些操作的场景。 - 队列和双端队列:
LinkedList
实现了Deque
接口,支持队列和双端队列的所有操作,非常适合用作队列或双端队列。 - 需要双向遍历:
LinkedList
支持双向遍历,可以通过ListIterator
实现向前和向后遍历。
Set (接口)
- Set接口简介
- 无序,没有索引
- 不允许重复元素,所以最多包含一个null
HashSet (Set实现类)
HashSet
是 Java 中一个非常重要的集合类,它实现了Set
接口,基于哈希表(HashMap
)实现。HashSet
不允许重复元素,并且不保证元素的顺序。以下是关于HashSet
的详细介绍,包括其特点、常用方法和使用示例。
1. 特点
- 不允许重复元素:
HashSet
中的元素必须是唯一的,重复的元素不会被添加。 - 无序性:
HashSet
不保证元素的顺序,元素的存储顺序可能与添加顺序不同。 - 基于哈希表实现:底层使用
HashMap
来存储元素,通过哈希函数将元素映射到哈希表中。 - 线程不安全:
HashSet
是线程不安全的,如果需要在多线程环境中使用,可以使用Collections.synchronizedSet
包装,或者使用线程安全的集合类(如ConcurrentHashMap
包装的Set
)。
2. 常用方法
以下是 HashSet
的一些常用方法:
2.1 添加元素
-
add(E e)
:向集合中添加一个元素。如果元素已存在,则不会添加,并返回false
。HashSet<String> set = new HashSet<>(); set.add("Apple"); set.add("Banana"); set.add("Cherry");
2.2 删除元素
-
remove(Object o)
:从集合中删除指定的元素。如果元素存在,则删除并返回true
;否则返回false
。set.remove("Banana");
2.3 检查元素
-
contains(Object o)
:检查集合中是否包含指定的元素。如果存在,则返回true
;否则返回false
。boolean containsApple = set.contains("Apple");
-
isEmpty()
:检查集合是否为空。如果集合为空,则返回true
;否则返回false
。boolean isEmpty = set.isEmpty();
2.4 获取集合大小
-
size()
:返回集合中的元素数量。int size = set.size();
2.5 清空集合
-
clear()
:清空集合中的所有元素。set.clear();
2.6 遍历集合
HashSet
可以通过多种方式遍历:
-
for-each
循环:for (String fruit : set) {System.out.println(fruit); }
-
Iterator
:Iterator<String> iterator = set.iterator(); while (iterator.hasNext()) {System.out.println(iterator.next()); }
-
Stream
API(Java 8及以上):set.stream().forEach(System.out::println);
3. 使用场景
- 去重:
HashSet
最常见的用途是去除重复元素。 - 快速查找:由于基于哈希表实现,
HashSet
提供了快速的查找性能(平均时间复杂度为 O(1))。 - 集合操作:可以方便地进行集合操作,如并集、交集、差集等。
Map(接口)
Java 中的 Map 接口 是一个非常重要的数据结构,用来存储键值对(Key-Value Pair)。下面我会用简单易懂的方式介绍它:
1. 什么是 Map 接口?
Map 是一个接口,它定义了一种数据结构,用来存储键(Key)和值(Value)的映射关系。每个键都对应一个值,就像一个字典,通过键来查找对应的值。
- 键(Key):必须是唯一的,不能重复。如果添加了重复的键,原来的键对应的值会被覆盖。
- 值(Value):可以重复,同一个值可以对应多个键。
2. 常见的 Map 实现类
Java 提供了几种常用的 Map 实现类,每种都有不同的特点:
- HashMap:
- 特点:基于哈希表实现,查找速度快,但不保证键值对的顺序。
- 用途:适合需要快速查找的场景,比如存储用户信息(用户名作为键,用户详情作为值)。
- TreeMap:
- 特点:基于红黑树实现,按键的自然顺序或指定的比较器排序。
- 用途:适合需要按键排序的场景,比如统计成绩并按分数排序。
- LinkedHashMap:
- 特点:基于哈希表和双向链表实现,保持插入顺序或访问顺序。
- 用途:适合需要保持插入顺序的场景,比如最近访问的网页记录。
HashMap类(map接口实现类)
HashMap
是Java集合框架中的一个类,用于存储键值对(key-value pairs)。它基于哈希表实现,允许快速插入、删除和查找操作。HashMap
允许一个null
键和多个null
值。
HashMap的主要特点
- 无序:
HashMap
不保证键值对的顺序。 - 允许null值和null键:可以有一个
null
键和多个null
值。 - 非同步:
HashMap
不是线程安全的。如果需要线程安全的操作,可以使用Collections.synchronizedMap
方法来包装HashMap
,或者使用ConcurrentHashMap
。 - 快速访问:通过哈希表实现,提供了快速的插入、删除和查找操作。
常用方法
put(K key, V value)
:将指定的值与该键关联。如果该键已存在,则更新其值。get(Object key)
:返回指定键所映射的值,如果此映射不包含该键的映射关系,则返回null
。remove(Object key)
:如果存在键的映射关系,则将其从映射中移除。containsKey(Object key)
:如果此映射包含指定键的映射关系,则返回true
。containsValue(Object value)
:如果此映射将一个或多个键映射到指定值,则返回true
。size()
:返回此映射中的键值对数量。isEmpty()
:如果此映射不包含键值对,则返回true
。clear()
:从此映射中移除所有键值对。
示例代码
下面是一个简单的HashMap
示例:
java复制
import java.util.HashMap;public class HashMapExample {public static void main(String[] args) {// 创建一个HashMap实例HashMap<String, Integer> map = new HashMap<>();// 添加键值对到HashMapmap.put("Apple", 10);map.put("Banana", 20);map.put("Orange", 30);map.put("Mango", 40);// 获取并打印值System.out.println("Value for key 'Apple': " + map.get("Apple"));// 检查是否包含某个键System.out.println("Contains key 'Banana': " + map.containsKey("Banana"));// 检查是否包含某个值System.out.println("Contains value 30: " + map.containsValue(30));// 移除键值对map.remove("Orange");// 遍历HashMapfor (String key : map.keySet()) {System.out.println("Key: " + key + ", Value: " + map.get(key));}// 打印HashMap的大小System.out.println("Size of the map: " + map.size());// 清空HashMapmap.clear();System.out.println("Is map empty? " + map.isEmpty());}
}
IO流
- 在Java中,IO(输入/输出)流是用于处理数据输入和输出的机制。Java提供了丰富的IO流类库,这些类库位于
java.io
包中。IO流可以分为两大类:字节流和字符流。字节流用于处理二进制数据,字符流用于处理文本数据。
以下是一些常见的IO流类及其用途:
字节流
InputStream
:抽象类,所有字节输入流的父类。OutputStream
:抽象类,所有字节输出流的父类。FileInputStream
:用于从文件中读取字节数据。FileOutputStream
:用于向文件写入字节数据。BufferedInputStream
:带有缓冲区的输入流,可以提高读取效率。BufferedOutputStream
:带有缓冲区的输出流,可以提高写入效率。
字符流
Reader
:抽象类,所有字符输入流的父类。Writer
:抽象类,所有字符输出流的父类。FileReader
:用于从文件中读取字符数据。FileWriter
:用于向文件写入字符数据。BufferedReader
:带有缓冲区的字符输入流,可以提高读取效率。BufferedWriter
:带有缓冲区的字符输出流,可以提高写入效率。
示例代码
以下是一些使用Java IO流的示例代码,展示如何读取和写入文件。
示例1:使用字节流读取和写入文件
java复制
import java.io.*;public class ByteStreamExample {public static void main(String[] args) {String inputFilePath = "input.txt";String outputFilePath = "output.txt";// 使用FileInputStream读取文件try (FileInputStream fis = new FileInputStream(inputFilePath);BufferedInputStream bis = new BufferedInputStream(fis)) {// 使用FileOutputStream写入文件try (FileOutputStream fos = new FileOutputStream(outputFilePath);BufferedOutputStream bos = new BufferedOutputStream(fos)) {int byteRead;while ((byteRead = bis.read()) != -1) {bos.write(byteRead);}System.out.println("File copied successfully!");} catch (IOException e) {System.err.println("Error writing to file: " + e.getMessage());}} catch (IOException e) {System.err.println("Error reading from file: " + e.getMessage());}}
}
示例2:使用字符流读取和写入文件
java复制
import java.io.*;public class CharStreamExample {public static void main(String[] args) {String inputFilePath = "input.txt";String outputFilePath = "output.txt";// 使用FileReader读取文件try (FileReader fr = new FileReader(inputFilePath);BufferedReader br = new BufferedReader(fr)) {// 使用FileWriter写入文件try (FileWriter fw = new FileWriter(outputFilePath);BufferedWriter bw = new BufferedWriter(fw)) {String line;while ((line = br.readLine()) != null) {bw.write(line);bw.newLine(); // 写入换行符}System.out.println("File copied successfully!");} catch (IOException e) {System.err.println("Error writing to file: " + e.getMessage());}} catch (IOException e) {System.err.println("Error reading from file: " + e.getMessage());}}
}
代码说明
try-with-resources
:Java 7引入的语法糖,用于自动关闭实现了AutoCloseable
接口的资源,如IO流。这样可以避免手动关闭流,减少代码量并提高安全性。- 缓冲流:
BufferedInputStream
和BufferedOutputStream
(或BufferedReader
和BufferedWriter
)可以提高读写效率,尤其是在处理大文件时。 - 异常处理:捕获
IOException
并打印错误信息。
注意事项
- 文件路径:确保文件路径正确,文件存在(对于输入文件)或可写(对于输出文件)。
- 字符编码:在处理文本文件时,字符流会自动处理字符编码。如果需要处理特定编码,可以使用
InputStreamReader
和OutputStreamWriter
指定编码。 - 资源管理:即使不使用
try-with-resources
,也应确保在finally
块中关闭流,以避免资源泄漏。