集合框架
数据
在Java中,数组是一种用来存储相同类型数据的数据结构。数组的大小在创建时就确定,并且不能动态改变。
声明和初始化数组
// 声明一个整型数组
int[] intArray;
// 初始化一个包含5个元素的整型数组
intArray = new int[5];
// 声明并初始化一个整型数组
int[] anotherArray = {1, 2, 3, 4, 5};
访问数组元素
int[] intArray = {10, 20, 30, 40, 50};
// 访问数组元素
int element = intArray[2]; // 获取第3个元素,值为30
遍历数组
int[] intArray = {10, 20, 30, 40, 50};
// 使用for循环遍历数组
for (int i = 0; i < intArray.length; i++) {
System.out.println(intArray[i]);
}
// 使用增强for循环遍历数组
for (int num : intArray) {
System.out.println(num);
}
数组实现对象的增删改查
增加对象
要向数组中添加新的对象,需要先创建一个新的数组,将原数组中的元素复制到新数组中,并在新数组末尾添加新的对象。
// 增加对象示例
// 假设有一个存储学生对象的数组
Student[] studentArray = new Student[3]; // 原数组大小为3
// 创建一个新的学生对象
Student newStudent = new Student("Alice", 20);
// 创建一个新的数组,大小比原数组大1
Student[] newStudentArray = new Student[studentArray.length + 1];
// 将原数组中的元素复制到新数组中
for (int i = 0; i < studentArray.length; i++) {
newStudentArray[i] = studentArray[i];
}
// 在新数组末尾添加新的学生对象
newStudentArray[studentArray.length] = newStudent;
// 将新数组赋值给原数组
studentArray = newStudentArray;
删除对象
要从数组中删除对象,需要找到要删除的对象在数组中的位置,然后创建一个新的数组,将原数组中除了要删除对象的元素复制到新数组中。
// 删除对象示例
// 假设有一个存储学生对象的数组
Student[] studentArray = {new Student("Alice", 20), new Student("Bob", 21), new Student("Charlie", 22)};
// 假设要删除Bob这个学生对象
String studentNameToDelete = "Bob";
// 找到要删除对象的位置
int indexToDelete = -1;
for (int i = 0; i < studentArray.length; i++) {
if (studentArray[i].getName().equals(studentNameToDelete)) {
indexToDelete = i;
break;
}
}
// 创建一个新的数组,大小比原数组小1
Student[] newStudentArray = new Student[studentArray.length - 1];
// 将原数组中除了要删除对象的元素复制到新数组中
int newIndex = 0;
for (int i = 0; i < studentArray.length; i++) {
if (i != indexToDelete) {
newStudentArray[newIndex] = studentArray[i];
newIndex++;
}
}
// 将新数组赋值给原数组
studentArray = newStudentArray;
修改对象
要修改数组中的对象,只需直接访问对象所在的位置,并进行修改。
// 修改对象示例
// 假设有一个存储学生对象的数组
Student[] studentArray = {new Student("Alice", 20), new Student("Bob", 21), new Student("Charlie", 22)};
// 假设要修改Bob这个学生对象的年龄为25
String studentNameToModify = "Bob";
int newAge = 25;
// 找到要修改对象的位置
for (int i = 0; i < studentArray.length; i++) {
if (studentArray[i].getName().equals(studentNameToModify)) {
studentArray[i].setAge(newAge);
break;
}
}
查找对象
要在数组中查找对象,需要遍历数组,逐个比较对象的属性与目标值。
// 查找对象示例
// 假设有一个存储学生对象的数组
Student[] studentArray = {new Student("Alice", 20), new Student("Bob", 21), new Student("Charlie", 22)};
// 假设要查找年龄为21的学生对象
int targetAge = 21;
// 遍历数组,逐个比较年龄属性
for (Student student : studentArray) {
if (student.getAge() == targetAge) {
System.out.println("找到年龄为21的学生:" + student.getName());
break;
}
}
注意事项
数组的下标从0开始。
数组一旦创建后,大小就固定了,不能动态改变。
数组中的元素必须是相同类型。
数组无法求出真实有效数据的个数
用数组实现对象的增删改查比较麻烦
java集合框架接口和类 关系图
Java集合框架接口和类关系图
+---------------------+
| Collection |
+----------+----------+
^
|
+----------+----------+
| |
| |
+---------+---------+ +-------+-------+
| | | |
| | | |
+---------+---------+ +-----+-----+ +---------+---------+
| List | | Set | | Queue |
+-------------------+ +-------------+ +-------------------+
| | | | | |
| | | | | |
| +----------------+ | | | | |
| | | | | | | |
| | | | | | | |
| | ArrayList | | | HashSet | | LinkedList |
| | LinkedList | | | TreeSet | | PriorityQueue |
| | Vector | | | | | |
| | Stack | | | | | |
| +----------------+ | | | | |
| | | | | |
+---------------------+ +-------------+ +-------------------+
Map
+---------+---------+
| |
| |
+---------+---------+ +-----+-----+
| Map | | SortedMap |
+-------------------+ +-------------+
| | | |
| | | |
| +----------------+ | | |
| | | | | |
| | | | | |
| | HashMap | | | TreeMap |
| | LinkedHashMap| | | |
| | Hashtable | | | |
| | ConcurrentHashMap | | |
| +----------------+ | | |
| | | |
+---------------------+ +-------------+
Collection
LinkedList
LinkedList 是 Java 集合框架中 List 接口的实现类,它基于双向链表实现。以下是关于 LinkedList 的特点:
可以高效地在列表的开头和结尾进行元素的插入和删除操作。
支持快速的随机访问,但效率比 ArrayList 低。
适用于需要频繁插入和删除操作的场景。
ArrayList
ArrayList 也是 Java 集合框架中 List 接口的实现类,它基于动态数组实现。以下是关于 ArrayList 的特点:
支持快速的随机访问,因为它基于数组实现。
在末尾进行元素的插入和删除操作效率高,但在中间插入和删除操作效率较低。
适用于需要频繁随机访问元素的场景。
HashSet
HashSet 是 Java 集合框架中 Set 接口的实现类,它基于哈希表实现。以下是关于 HashSet 的特点:
不允许存储重复元素。
不保证集合中元素的顺序,即不保证元素的插入顺序和遍历顺序一致。
适用于需要快速查找元素且不关心元素顺序的场景。
TreeSet
TreeSet 是 Java 集合框架中 Set 接口的实现类,它基于红黑树实现。以下是关于 TreeSet 的特点:
TreeSet 是有序的,它会根据元素的自然顺序或者自定义比较器来维护元素的顺序。
不允许存储重复元素。
适用于需要有序存储元素的场景。
两个 Queue
LinkedList 实现的 Queue
LinkedList 也可以用来实现 Queue 接口,作为队列使用。以下是关于 LinkedList 实现的 Queue 的特点:
支持队列的基本操作,如入队(offer)、出队(poll)、获取队首元素(peek)等。
可以实现先进先出(FIFO)的队列。
PriorityQueue
PriorityQueue 是 Java 集合框架中 Queue 接口的实现类,它是一个优先级队列。以下是关于 PriorityQueue 的特点:
PriorityQueue 是基于堆实现的,可以按照元素的优先级顺序进行出队操作。
元素根据其自然顺序或者自定义比较器来确定优先级。
适用于需要按照优先级顺序处理元素的场景。
迭代器
迭代器(Iterator)是集合框架中的一个接口,用于遍历集合中的元素。通过迭代器,可以依次访问集合中的每个元素,而不需要了解集合的内部结构。
迭代器接口定义了以下常用方法:
boolean hasNext():判断集合中是否还有下一个元素。E next():返回集合中的下一个元素,并将迭代器的指针向后移动一位。void remove():从集合中删除迭代器返回的最后一个元素(可选操作)。
以下是一个使用迭代器遍历集合的示例代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
// 使用迭代器遍历集合
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}
}
}
在上面的示例中,我们创建了一个ArrayList集合,并向其中添加了三个元素。然后,我们通过调用iterator()方法获取集合的迭代器对象。接下来,我们使用while循环和hasNext()方法判断集合中是否还有下一个元素,如果有,则使用next()方法获取下一个元素并打印出来。
需要注意的是,在使用迭代器遍历集合时,如果在遍历过程中修改了集合的结构(如添加或删除元素),会抛出ConcurrentModificationException异常。如果需要在遍历过程中修改集合,可以使用迭代器的remove()方法来删除元素。
增强for循环
增强 for 循环
增强 for 循环(也称为“for-each”循环)是 Java 中用于遍历集合和数组的一种简化语法。它使得遍历集合或数组的代码更加简洁和易读。增强 for 循环的语法如下:
for (元素类型 元素 : 集合或数组) {
// 对元素的操作
}
特点
简洁性:增强 for 循环不需要使用索引或迭代器,代码更加简洁。
可读性:增强 for 循环的语法更接近自然语言,易于理解。
安全性:在遍历过程中不容易出现越界或其他常见错误。
示例代码
以下是一个使用增强 for 循环遍历 ArrayList 的示例:
import java.util.ArrayList;
import java.util.List;
public class EnhancedForLoopExample {
public static void main(String[] args) {
// 创建一个 ArrayList 并添加元素
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
// 使用增强 for 循环遍历集合
for (String fruit : fruits) {
System.out.println(fruit);
}
}
}
输出结果
Apple
Banana
Orange
遍历数组的示例
增强 for 循环同样适用于数组,以下是一个遍历整型数组的示例:
public class EnhancedForLoopArrayExample {
public static void main(String[] args) {
// 声明并初始化一个整型数组
int[] numbers = {1, 2, 3, 4, 5};
// 使用增强 for 循环遍历数组
for (int number : numbers) {
System.out.println(number);
}
}
}
输出结果
1
2
3
4
5
注意事项
增强 for 循环只能用于读取元素,不能用于修改集合或数组的结构(如添加或删除元素)。
如果需要在遍历过程中修改集合的内容,建议使用传统的 for 循环或迭代器。
增强 for 循环是 Java 中非常实用的特性,能够提高代码的可读性和简洁性,适合用于大多数遍历场景。
泛型
泛型是 Java 中的一种特性,它允许在类、接口和方法中定义类型参数,从而使代码更加灵活和可重用。通过使用泛型,可以在编译时检查类型安全,避免在运行时出现类型转换异常。
泛型的优点
类型安全:使用泛型可以在编译时检查类型,减少运行时错误。
代码重用:可以编写通用的算法和数据结构,适用于多种类型。
消除强制类型转换:使用泛型后,不需要在使用集合时进行类型转换,代码更加简洁。
泛型类
泛型类是指在类定义时使用类型参数的类。以下是一个简单的泛型类示例:
// 定义一个泛型类 Box
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
// 使用泛型类
public class GenericClassExample {
public static void main(String[] args) {
// 创建一个 Box 对象,存储 String 类型
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello, Generics!");
System.out.println(stringBox.getItem());
// 创建一个 Box 对象,存储 Integer 类型
Box<Integer> integerBox = new Box<>();
integerBox.setItem(123);
System.out.println(integerBox.getItem());
}
}
输出结果
Hello, Generics!
123
泛型方法
泛型方法是指在方法定义时使用类型参数的方法。以下是一个泛型方法的示例:
// 定义一个泛型方法
public class GenericMethodExample {
// 泛型方法,接受一个数组并打印数组中的元素
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
public static void main(String[] args) {
// 创建一个字符串数组
String[] stringArray = {"Apple", "Banana", "Orange"};
printArray(stringArray); // 调用泛型方法
// 创建一个整型数组
Integer[] intArray = {1, 2, 3, 4, 5};
printArray(intArray); // 调用泛型方法
}
}
输出结果
Apple
Banana
Orange
1
2
3
4
5
泛型接口
泛型接口是指在接口定义时使用类型参数的接口。以下是一个泛型接口的示例:
// 定义一个泛型接口
interface Pair<K, V> {
K getKey();
V getValue();
}
// 实现泛型接口
class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
// 使用泛型接口
public class GenericInterfaceExample {
public static void main(String[] args) {
Pair<String, Integer> pair = new OrderedPair<>("One", 1);
System.out.println("Key: " + pair.getKey() + ", Value: " + pair.getValue());
}
}
输出结果
Key: One, Value: 1
注意事项
类型参数的命名:通常使用单个大写字母表示类型参数,如
T(类型)、K(键)、V(值)等。不能使用基本数据类型:泛型只能使用对象类型,不能使用基本数据类型(如
int、char等),可以使用其包装类(如Integer、Character等)。类型擦除:Java 的泛型在编译时会进行类型擦除,运行时不保留泛型信息,因此不能使用
instanceof检查泛型类型。
泛型是 Java 中非常强大且灵活的特性,能够提高代码的可读性和可维护性。
数据工具类Arrays
Arrays 类
java.util.Arrays 是 Java 集合框架中的一个工具类,提供了一系列静态方法用于操作数组。它包含了用于数组排序、搜索、比较等操作的方法。
常用方法
排序
public static void sort(int[] a):对指定的 int 数组进行升序排序。public static void sort(Object[] a):对指定的对象数组进行升序排序,要求数组中的元素实现了Comparable接口。public static <T> void sort(T[] a, Comparator<? super T> c):对指定的对象数组进行排序,使用指定的比较器。
搜索
public static int binarySearch(int[] a, int key):在指定的 int 数组中使用二分搜索算法搜索指定的值。public static int binarySearch(Object[] a, Object key):在指定的对象数组中使用二分搜索算法搜索指定的值,要求数组中的元素实现了Comparable接口。public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c):在指定的对象数组中使用二分搜索算法搜索指定的值,使用指定的比较器。
比较
public static boolean equals(int[] a, int[] a2):比较两个 int 数组是否相等。public static boolean equals(Object[] a, Object[] a2):比较两个对象数组是否相等。
示例代码
排序示例
import java.util.Arrays;
public class ArraysExample {
public static void main(String[] args) {
int[] numbers = {5, 3, 9, 1, 7};
Arrays.sort(numbers);
System.out.println("Sorted numbers: " + Arrays.toString(numbers));
String[] names = {"Alice", "Bob", "Charlie", "David"};
Arrays.sort(names);
System.out.println("Sorted names: " + Arrays.toString(names));
}
}
搜索示例
import java.util.Arrays;
public class ArraysSearchExample {
public static void main(String[] args) {
int[] numbers = {5, 3, 9, 1, 7};
Arrays.sort(numbers);
int index = Arrays.binarySearch(numbers, 3);
System.out.println("Index of 3: " + index);
String[] names = {"Alice", "Bob", "Charlie", "David"};
Arrays.sort(names);
index = Arrays.binarySearch(names, "Bob");
System.out.println("Index of Bob: " + index);
}
}
比较示例
import java.util.Arrays;
public class ArraysEqualsExample {
public static void main(String[] args) {
int[] numbers1 = {1, 2, 3};
int[] numbers2 = {1, 2, 3};
System.out.println("Are numbers1 and numbers2 equal? " + Arrays.equals(numbers1, numbers2));
String[] names1 = {"Alice", "Bob", "Charlie"};
String[] names2 = {"Alice", "Bob", "Charlie"};
System.out.println("Are names1 and names2 equal? " + Arrays.equals(names1, names2));
}
}
在上述示例中,我们演示了 Arrays 类的排序、搜索和比较操作。通过调用 sort 方法对数组进行排序,使用 binarySearch 方法进行搜索,以及使用 equals 方法比较数组是否相等。
集合工具类Collections
Collections 类
java.util.Collections 是 Java 集合框架中的一个工具类,提供了一系列静态方法,用于对集合进行各种操作,如排序、查找、替换等。Collections 类中的方法都是静态的,可以直接通过类名调用。
常用方法
排序
sort(List<T> list):对列表进行排序,要求列表中的元素必须实现Comparable接口。sort(List<T> list, Comparator<? super T> c):对列表进行排序,使用自定义的比较器进行排序。
查找和替换
binarySearch(List<? extends Comparable<? super T>> list, T key):使用二分查找算法在有序列表中查找指定元素。replaceAll(List<T> list, T oldVal, T newVal):将列表中所有的旧元素替换为新元素。
同步控制
synchronizedCollection(Collection<T> c):返回指定集合的同步(线程安全)视图。synchronizedList(List<T> list):返回指定列表的同步(线程安全)视图。
不可变集合
unmodifiableCollection(Collection<? extends T> c):返回指定集合的不可变视图。unmodifiableList(List<? extends T> list):返回指定列表的不可变视图。
其他
reverse(List<?> list):反转列表中元素的顺序。shuffle(List<?> list):随机打乱列表中元素的顺序。copy(List<? super T> dest, List<? extends T> src):将源列表中的元素复制到目标列表中。
示例代码
排序示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsExample {
public static void main(String[] args) {
// 创建一个整型列表
List<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(8);
numbers.add(3);
// 对列表进行排序
Collections.sort(numbers);
System.out.println("排序后的列表:" + numbers);
}
}
查找和替换示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsExample {
public static void main(String[] args) {
// 创建一个字符串列表
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add("David");
// 在有序列表中查找指定元素
int index = Collections.binarySearch(names, "Charlie");
System.out.println("元素 Charlie 的索引位置:" + index);
// 将列表中所有的旧元素替换为新元素
Collections.replaceAll(names, "Bob", "Eve");
System.out.println("替换后的列表:" + names);
}
}
同步控制示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsExample {
public static void main(String[] args) {
// 创建一个字符串列表
List<String> colors = new ArrayList<>();
colors.add("Red");
colors.add("Green");
colors.add("Blue");
// 获取同步视图
List<String> synchronizedColors = Collections.synchronizedList(colors);
// 在同步视图上进行安全操作
synchronized (synchronizedColors) {
for (String color : synchronizedColors) {
System.out.println(color);
}
}
}
}
不可变集合示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsExample {
public static void main(String[] args) {
// 创建一个整型列表
List<Integer> originalList = new ArrayList<>();
originalList.add(1);
originalList.add(2);
originalList.add(3);
// 获取不可变视图
List<Integer> unmodifiableList = Collections.unmodifiableList(originalList);
// 尝试修改不可变视图
// unmodifiableList.add(4); // 会抛出 UnsupportedOperationException 异常
}
}
其他示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsExample {
public static void main(String[] args) {
// 创建一个整型列表
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
// 反转列表中元素的顺序
Collections.reverse(numbers);
System.out.println("反转后的列表:" + numbers);
// 随机打乱列表中元素的顺序
Collections.shuffle(numbers);
System.out.println("打乱后的列表:" + numbers);
}
}
以上示例代码演示了 Collections 类中部分常用方法的使用,包括排序、查找和替换、同步控制、不可变集合、反转和打乱等操作。通过 Collections 类提供的丰富功能,可以方便地对集合进行各种操作,提高代码的效率和可维护性。
比较器Comparable和Comparator
在Java中,Comparable和Comparator是用于对象排序的两个接口。它们的主要区别在于实现方式和使用场景。
Comparable 接口
Comparable接口用于定义对象的自然排序。实现该接口的类需要重写compareTo方法,该方法用于比较当前对象与指定对象的大小关系。
特点
自然排序:实现
Comparable接口的类可以直接进行排序。单一排序方式:每个类只能有一个自然排序方式。
示例代码
class Student implements Comparable<Student> {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public int compareTo(Student other) {
// 按年龄升序排序
return Integer.compare(this.age, other.age);
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class ComparableExample {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("Alice", 20));
students.add(new Student("Bob", 22));
students.add(new Student("Charlie", 21));
// 使用 Collections.sort() 进行排序
Collections.sort(students);
// 输出排序结果
for (Student student : students) {
System.out.println(student);
}
}
}
输出结果
Alice (20)
Charlie (21)
Bob (22)
Comparator 接口
Comparator接口用于定义对象的自定义排序。实现该接口的类需要重写compare方法,该方法用于比较两个对象的大小关系。
特点
自定义排序:可以根据需要定义多种排序方式。
灵活性:可以在不修改类的情况下对对象进行排序。
示例代码
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
class AgeComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
// 按年龄升序排序
return Integer.compare(s1.getAge(), s2.getAge());
}
}
class NameComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
// 按姓名字母顺序排序
return s1.getName().compareTo(s2.getName());
}
}
public class ComparatorExample {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("Alice", 20));
students.add(new Student("Bob", 22));
students.add(new Student("Charlie", 21));
// 按年龄排序
Collections.sort(students, new AgeComparator());
System.out.println("按年龄排序:");
for (Student student : students) {
System.out.println(student);
}
// 按姓名排序
Collections.sort(students, new NameComparator());
System.out.println("按姓名排序:");
for (Student student : students) {
System.out.println(student);
}
}
}
输出结果
按年龄排序:
Alice (20)
Charlie (21)
Bob (22)
按姓名排序:
Alice (20)
Bob (22)
Charlie (21)
总结
Comparable接口用于定义对象的自然排序,适用于单一排序方式。Comparator接口用于定义自定义排序,适用于多种排序方式。
Comments