Collections类
- Collections类是Java集合框架中的一个工具类,提供了一系列静态方法,用于对集合进行操作和算法处理。
- 它包含了一些常见的算法,如排序、查找、比较等,还提供了一些用于创建和操作集合的方法。
以下是一些常用的方法:
- sort(List list):对列表进行升序排序。
- reverse(List list):将列表中的元素反转。
- shuffle(List list):将列表中的元素随机重新排序。
- binarySearch(List<?> list, T key):使用二分查找算法在列表中查找指定元素。
- max(Collection<? extends T> coll):返回集合中的最大元素。
- min(Collection<? extends T> coll):返回集合中的最小元素。
下面是使用Collections类的示例:
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(3);
numbers.add(8);
numbers.add(1);
// 使用sort方法对列表进行排序
Collections.sort(numbers);
System.out.println(numbers); // 输出:[1, 3, 5, 8]
// 使用max方法获取列表中的最大元素
int max = Collections.max(numbers);
System.out.println("最大值:" + max); // 输出:最大值:8
}
}
Comparable接口:
- Comparable接口是Java类的一个接口。
- 它定义了一个compareTo()方法,使得类的对象可以与其他对象进行比较。
- 实现Comparable接口的类可以通过自己定义的排序规则来进行比较和排序。
- compareTo()方法的返回值为整型,它表示了当前对象与另一个对象的比较结果。
常见的返回值包括:
- 当返回值为负数时,表示当前对象小于另一个对象。
- 当返回值为零时,表示当前对象等于另一个对象。
- 当返回值为正数时,表示当前对象大于另一个对象。
以下是使用Comparable接口的示例:
import java.util.Arrays;
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student other) {
// 按照年龄升序排序
return this.age - other.age;
}
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
public static void main(String[] args) {
Student student1 = new Student("John", 20);
Student student2 = new Student("Alice", 18);
Student student3 = new Student("Bob", 22);
Student[] students = {student1, student2, student3};
Arrays.sort(students); // 使用compareTo方法进行排序
for (Student student : students) {
System.out.println(student);
}
// 输出:
// Student{name='Alice', age=18}
// Student{name='John', age=20}
// Student{name='Bob', age=22}
}
}
Comparator接口:
- Comparator接口也用于进行对象的比较和排序。
- 不同于Comparable接口,Comparator接口的排序规则可以在对象之外定义。
- Comparator接口定义了两个方法:compare()和equals()。
- compare()方法与compareTo()方法类似,返回值也表示了两个对象的比较结果。
- 与Comparable接口不同的是,compare()方法可以被用于任意的对象进行比较。
以下是使用Comparator接口的示例:
import java.util.Arrays;
import java.util.Comparator;
public 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 "Student{name='" + name + "', age=" + age + "}";
}
public static void main(String[] args) {
Student student1 = new Student("John", 20);
Student student2 = new Student("Alice", 18);
Student student3 = new Student("Bob", 22);
Student[] students = {student1, student2, student3};
// 按照姓名升序排序
Arrays.sort(students, new Comparator<Student>() {
public int compare(Student student1, Student student2) {
return student1.getName().compareTo(student2.getName());
}
});
for (Student student : students) {
System.out.println(student);
}
// 输出:
// Student{name='Alice', age=18}
// Student{name='Bob', age=22}
// Student{name='John', age=20}
}
}
在上述示例中,通过创建一个匿名内部类实现了Comparator接口的compare()方法,定义了按照姓名升序排序的规则。然后将该Comparator对象作为参数传递给Arrays.sort()方法,即可使用自定义规则对对象数组进行排序。
泛型机制
- 泛型是java 1.5引入的新特性,泛型的本质是参数类型化。在类,接口和方法的定义过程中,所操作的数据类型被传入的参数指定。
- java泛型机制广泛低应用于集合中,所有集合类型都带有泛型, 在创建集合对象的时候,指定集合中元素的类型。
- java编译器根据泛型的类型,对集合中元素进行类型检查,减少运行的时候错误。
// class 类名<泛型> -- 泛型代表一种类型, 相当于是一个参数. 类定义的时候,不知道具
//体的类型. 使用类来创建对象的时候,在指定具体类型.
class MyDog<D>{
D d;
public MyDog(D d){
this.d = d;
}
}
collection集合
Java Collection接口的常用方法
-
创建对象:
Collection<String> c = new ArrayList<>();
-
获取集合中元素的个数:
int size = c.size();
-
判断集合是否为空:
boolean isEmpty = c.isEmpty();
-
判断集合是否包含指定元素:
boolean containsElement = c.contains("内容");
-
添加元素:
c.add("内容");
-
批量添加元素:
Collection<String> collectionToAdd = new ArrayList<>(); collectionToAdd.add("元素1"); collectionToAdd.add("元素2"); c.addAll(collectionToAdd);
-
删除指定元素:
c.remove("内容");
-
批量删除元素:
Collection<String> collectionToRemove = new ArrayList<>(); collectionToRemove.add("元素1"); collectionToRemove.add("元素2"); c.removeAll(collectionToRemove);
-
清空集合:
c.clear();
-
迭代集合:
Iterator<String> iterator = c.iterator(); while (iterator.hasNext()) { String element = iterator.next(); // 在迭代过程中对元素进行操作 }
这些方法适用于Collection接口的各个实现类,如ArrayList、LinkedList、HashSet等。通过调用这些方法,可以对集合进行元素的添加、删除、判断和遍历操作。
Collection的遍历方式
当需要遍历Collection集合中的元素时,有三种常见的方法:迭代器(Iterator)、增强for循环(Enhanced for loop)和lambda表达式。
一、 迭代器(Iterator):
- 迭代器是一个对象,用于按顺序遍历集合中的元素。
- 它提供了hasNext()方法用于检查是否还有下一个元素,以及next()方法用于获取下一个元素。
- 使用迭代器遍历集合的步骤一般为:
通过调用集合的iterator()方法获取迭代器对象,然后使用while循环和迭代器的hasNext()和next()方法完成遍历。
示例代码:
Collection<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);
}
二、增强for循环(Enhanced for loop):
- 增强for循环是一种简化迭代器遍历过程的语法,在Java5引入。
- 它提供了更简洁的语法来遍历集合或数组的元素。
- 使用增强for循环遍历集合时,语法为:for (元素类型 元素变量 : 集合变量)。
示例代码:
Collection<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
for (String element : list) {
System.out.println(element);
}
三、lambda表达式:
- lambda表达式是Java8引入的一种函数式编程语法,用于简化代码。
- 它可以用于遍历集合,并通过函数式接口的方式定义遍历时的操作。
- 使用lambda表达式遍历集合时,可以结合forEach()方法来完成遍历。
示例代码:
Collection<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
list.forEach(element -> System.out.println(element));
List集合
- 在Java中,List是一个接口,它继承自Collection接口,代表一个有序的集,可以包含重复元素。
- 由于List集合是有序的,它支持索引,因此提供了一些与索引相关的方法。
List系列集合特点: 有序,可重复,有索引
- ArrayList:有序,可重复,有索引。
- LinkedList:有序,可重复,有索引。
List集合的特有方法
- List集合因为支持索引,所以多了很多与索引相关的方法。
- 当然,Collection的功能List也都继承了。
下面是一些常用的与索引相关的List方法:
- add(int index, E element):在指定索引位置插入元素。
List<String> list = new ArrayList<>();
list.add("Apple"); // ["Apple"]
list.add("Banana"); // ["Apple", "Banana"]
list.add(1, "Orange"); // ["Apple", "Orange", "Banana"]
- get(int index):根据索引获取列表中的元素。
List<String> list = new ArrayList<>();
list.add("Apple"); // ["Apple"]
list.add("Banana"); // ["Apple", "Banana"]
String fruit = list.get(1); // 获取索引为1的元素
System.out.println(fruit); // 输出:Banana
- set(int index, E element):将指定索引处的元素替换为新元素。
List<String> list = new ArrayList<>();
list.add("Apple"); // ["Apple"]
list.add("Banana"); // ["Apple", "Banana"]
list.set(1, "Orange"); // 将索引为1处的元素替换为Orange
System.out.println(list); // 输出:["Apple", "Orange"]
- remove(int index):根据索引移除列表中的元素。
List<String> list = new ArrayList<>();
list.add("Apple"); // ["Apple"]
list.add("Banana"); // ["Apple", "Banana"]
String removedElement = list.remove(0); // 移除索引为0的元素
System.out.println(removedElement); // 输出:Apple
System.out.println(list); // 输出:["Banana"]
- indexOf(Object o):返回指定元素第一次出现的索引。
List<String> list = new ArrayList<>();
list.add("Apple"); // ["Apple"]
list.add("Banana"); // ["Apple", "Banana"]
list.add("Orange"); // ["Apple", "Banana", "Orange"]
int index = list.indexOf("Banana"); // 获取元素"Banana"的索引
System.out.println(index); // 输出:1
- lastIndexOf(Object o):返回指定元素最后一次出现的索引。
List<String> list = new ArrayList<>();
list.add("Apple"); // ["Apple"]
list.add("Banana"); // ["Apple", "Banana"]
list.add("Orange"); // ["Apple", "Banana", "Orange"]
list.add("Banana"); // ["Apple", "Banana", "Orange", "Banana"]
int lastIndex = list.lastIndexOf("Banana"); // 获取元素"Banana"最后一次出现的索引
System.out.println(lastIndex); // 输出:3
List集合的遍历方式
Java中的List集合支持多种遍历方式,包括:
一、for循环:可以通过索引访问List集合中的元素。
示例代码如下:
List<String> list = Arrays.asList("apple", "banana", "orange");
for (int i = 0; i < list.size(); i++) {
String item = list.get(i);
System.out.println(item);
}
二、迭代器(Iterator)
使用迭代器遍历集合可以在遍历的同时进行增删操作,并且适用于所有实现了Iterable接口的集合类。
示例代码如下:
List<String> list = Arrays.asList("apple", "banana", "orange");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
三、增强for循环(foreach循环)
使用增强for循环(foreach循环)简化了迭代器的使用,可以直接遍历集合中的元素。
示例代码如下:
List<String> list = Arrays.asList("apple", "banana", "orange");
for (String item : list) {
System.out.println(item);
}
四、Lambda表达式(Java 8及以上版本)
使用Lambda表达式(Java 8及以上版本):可以使用Lambda表达式对集合进行遍历和处理,非常简洁和方便。
示例代码如下:
List<String> list = Arrays.asList("apple", "banana", "orange");
list.forEach(item -> System.out.println(item));
ArrayList集合的底层原理
利用无参构造器创建的集合,会在底层创建一个默认长度为0的数组
添加第一个元素时,底层会创建一个新的长度为10的数组
存满时,会扩容1.5倍
如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准
- 基于数组实现的。
- 查询速度快(注意:是根据索引查询数据快):查询数据通过地址值和索引定位,查询任意数据耗时相同。
- 删除效率低:可能需要把后面很多的数据进行前移。
- 添加效率极低:可能需要把后面很多的数据后移,再添加元素;或者也可能需要进行数组的扩容。
LinkedList集合的底层原理
- 基于双链表实现的。
链表的特点1:查询慢,无论查询哪个数据都要从头开始找。
链表的特点2:链表增删相对快
- 特点:查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的。
- LinkedList新增了:很多首尾操作的特有方法。
方法名称 | 说明 |
---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
LinkedList的应用场景
可以用来设计队列
- 队列是常用的数据结构,可以将队列堪称是特殊的线性表,队列只能从一端添加元素(offer),另 一端取出元素(poll)
- 队列遵循先进先出的原则(FIFO, first in first out)
- Queue是jdk中的接口, LinkedList是Queue的实现类
- Queue接口中的主要方法
- 创建对象:
要创建一个队列对象,可以使用Queue接口的实现类,常见的选择是LinkedList。可以使用以下代码创建一个队列对象:
Queue<类型> 变量名 = new LinkedList<>();
例如,创建一个整数类型的队列对象:
Queue<Integer> queue = new LinkedList<>();
- 元素进队:
要将元素添加到队列中,可以使用offer()方法。它将指定的元素添加到队列的末尾。
变量名.offer("元素");
例如,将字符串元素添加到队列中:
queue.offer("A");
queue.offer("B");
queue.offer("C");
- 元素出队:
要获取队列中的元素并将其移除,可以使用peek()方法。它返回队列的头部元素,但不会将其从队列中移除。
变量名.peek();
例如,获取队列中的第一个元素:
String firstElement = queue.peek();
- 删除队首元素:
要获取队列中的头部元素并将其移除,可以使用poll()方法。它返回队列的头部元素,并将其从队列中移除。
变量名.poll();
例如,删除队列中的第一个元素:
String removedElement = queue.poll();
import java.util.Queue;
import java.util.LinkedList;
public class QueueExample {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
// 元素进队
queue.offer("A");
queue.offer("B");
queue.offer("C");
// 元素出队
String firstElement = queue.peek();
System.out.println("第一个元素:" + firstElement);
// 删除队首元素
String removedElement = queue.poll();
System.out.println("删除的元素:" + removedElement);
}
}
上述示例展示了如何创建一个队列对象,并进行元素进队和出队操作。
可以用来设计栈
- Deque是Queue的子接口, 被称为双端队列,即可以从队列的两端入队(offer),出队(poll),LinkedList实现了该接口。
- 将Deque限定为为只能从一端出队和入队,就可以模拟栈的数据结构,栈数据结构,入栈为push,出栈为pop.
- 栈遵循先进后出的原则FILO(first int last out)
Deque提供了以下常用方法来操作栈:
- 创建对象:
使用LinkedList类实现Deque接口来创建栈对象,示例代码如下:
Deque<String> stack = new LinkedList<>();
- 压入元素:
使用push()方法将元素压入栈中。它将元素添加到栈的顶部。
stack.push("Element 1");
stack.push("Element 2");
- 弹出元素:
使用pop()方法从栈中弹出元素。它删除并返回栈顶的元素。
String element = stack.pop();
System.out.println(element); // 输出:Element 2
在调用pop()方法时,栈必须包含至少一个元素。如果栈为空,继续弹出元素将抛出NoSuchElementException异常。
import java.util.Deque;
import java.util.LinkedList;
public class StackExample {
public static void main(String[] args) {
Deque<String> stack = new LinkedList<>();
// 压入元素
stack.push("Element 1");
stack.push("Element 2");
stack.push("Element 3");
// 弹出元素
String element = stack.pop();
System.out.println(element); // 输出:Element 3
// 再次弹出元素
element = stack.pop();
System.out.println(element); // 输出:Element 2
}
}
在上述示例中,我们创建了一个栈对象,并在栈中压入了三个元素。然后我们连续两次弹出了栈顶的元素,并分别打印了弹出的元素。
set集合
注意:
Set要用到的常用方法,基本上就是Collection提供的!!
Set系列集合特点:无序:添加数据的顺序和获取出的数据顺序不一致; 不重复; 无索引。
- HashSet : 无序、不重复、无索引。
- LinkedHashSet:有序、不重复、无索引。
- TreeSet:排序、不重复、无索引。
HashSet集合的底层原理
- 基于哈希表实现。
- 哈希表是一种增删改查数据,性能都较好的数据结构。
哈希值
- 就是一个int类型的数值,Java中每个对象都有一个哈希值。
- Java中的所有对象,都可以调用Obejct类提供的hashCode方法,返回该对象自己的哈希值。
public int hashCode():返回对象的哈希码值。
1、对象哈希值的特点
-
同一个对象多次调用hashCode()方法返回的哈希值是相同的。
-
不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞)。
2、 哈希表的详细流程
-
创建一个默认长度16,默认加载因为0.75的数组,数组名table
-
根据元素的哈希值跟数组的长度计算出应存入的位置
-
判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素,
则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组。 -
当数组存满到16*0.75=12时,就自动扩容,每次扩容原先的两倍
LinkedHashSet集合
- 依然是基于哈希表(数组、链表、红黑树)实现的。
- 但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
TreeSet集合
- 底层是基于红黑树实现的排序。
- 特点:不重复、无索引、可排序(默认升序排序 ,按照元素的大小,由小到大排序)