Collection集合介绍
Collection【接口】:
我们通过帮助文档发现,Collection是一个接口,不能直接new对象
根据元素是否可以发生重复,继续分类
- List【接口】元素可以发生重复,且有索引的概念
ArrayList
- Set【接口】元素不可以发生重复,没有索引
借助 ArrayList 子类对象来使用 Collection 接口中的方法
学习 Java 中任意一个集合的步骤:
- 创建相关集合对象。
- 创建元素对象。
- 将元素添加到集合中。
- 遍历集合。
Collection 中的成员方法:
boolean add(E e)
:向集合中添加元素。boolean remove(Object o)
:从集合中移除元素。void clear()
:清空集合。boolean contains(Object o)
:判断某元素是否在集合中。boolean isEmpty()
:判断集合是否为空。int size()
:获取集合长度(元素个数)。
public class CollectionDemo1 {
public static void main(String[] args) {
//借助ArrayList创建对象来使用Collection接口中的方法
// 1、创建相关集合对象
Collection c1 = new ArrayList();
//boolean add(Object e)
c1.add(100); //这里涉及到自动装箱 int -> Integer
c1.add(true);
c1.add(12.34);
c1.add(1000L);
c1.add(100);
c1.add(12.34);
// 重写toString()方法的类是ArrayList类的父类的父类中重写的。
// 底层是使用StringBuilder实现的
System.out.println("c1: " + c1);
//注意:我们今后使用集合的时候,规定一个集合只能存储一种数据类型的元素
System.out.println("-----------------------------------------");
//[100, true, 12.34, 1000, 100, 12.34]
//boolean remove(Object o) 从集合中删除一个元素,只会删除最左边的一个匹配元素
c1.remove(100);
System.out.println("c1: " + c1);
System.out.println("-----------------------------------------");
//void clear() 清空集合元素
// c1.clear();
// System.out.println("c1: " + c1);
System.out.println("-----------------------------------------");
//boolean contains(Object o) 判断Collection集合中是否包含某个元素
System.out.println(c1.contains(12.34));
System.out.println("-----------------------------------------");
//boolean isEmpty() 判断Collection集合是否为空
System.out.println(c1.isEmpty());
System.out.println("-----------------------------------------");
//int size() 获取集合的长度【元素的个数】
System.out.println(c1.size());
}
}
注意
在使用集合的时候,规定一个集合只能存储一种类型的数据元素。
List 集合详解
在 Java 中,List
是 Collection
接口的一个子接口,它表示一个元素有序、可重复的集合。List
接口有三个主要的实现类:ArrayList
、Vector
和 LinkedList
。这些类提供了不同的性能特点和线程安全特性。
List 集合的特点
- 元素有序:
List
集合中的元素有顺序,可以通过索引访问。 - 元素可重复:
List
集合允许存储重复的元素。 - 索引访问:可以通过索引快速访问集合中的元素。
List 集合的实现类
ArrayList 类
- 底层数据结构:动态数组
- 特点:查询速度快,增删操作相对较慢,线程不安全,但效率高。
- 使用场景:适用于频繁读取,较少修改的场景。
Vector 类
- 底层数据结构:动态数组
- 特点:查询速度快,增删操作相对较慢,线程安全,但效率较低。
- 使用场景:适用于多线程环境,需要线程安全的场景。
LinkedList 类
- 底层数据结构:双向链表
- 特点:增删操作快,查询操作慢,线程不安全,效率高。
- 使用场景:适用于频繁插入和删除的场景。
List 集合的常用方法
add(E e)
:向集合中添加元素。remove(Object o)
:从集合中移除元素。clear()
:清空集合。contains(Object o)
:检查集合是否包含某个元素。isEmpty()
:检查集合是否为空。size()
:获取集合中元素的数量。addAll(Collection c)
:将另一个集合中的所有元素添加到当前集合。removeAll(Collection c)
:移除当前集合中所有存在于指定集合的元素。containsAll(Collection c)
:检查当前集合是否包含指定集合的所有元素。retainAll(Collection c)
:保留当前集合中所有存在于指定集合的元素。
public class Demo1Collection {
public static void main(String[] args) {
//由于Collection是一个接口,List接口继承了Collection,而实现List接口的具体类是ArrayList
// 所以使用多态,借助ArrayList创建对象来使用Collection接口中的方法
Collection c1 = new ArrayList();//父类的引用指向子类对象
//在集合中添加元素
c1.add(100);//这里涉及到自动装箱int-->Integer
c1.add(true);
c1.add(12.34);
c1.add(1000L);
c1.add(100);
c1.add(12.34);
System.out.println(c1);//重写toString方法的类是ArrayList类的父类的父类中重写的,底层使用的是StringBuffer实现的
c1.remove(100);//若有重复的只会删除第一个找到的元素
System.out.println(c1);
System.out.println(c1.contains(100));//判断集合中是否包含某元素
System.out.println(c1.isEmpty());//判断集合是否为空
System.out.println(c1.size());//获取集合的长度
}
}
public class Demo2Collection {
public static void main(String[] args) {
//创建结合对象
Collection c1 = new ArrayList();
c1.add("java");
c1.add("maven");
c1.add("clickhouse");
c1.add("redis");
Collection c2 = new ArrayList();
c2.add("java");
c2.add("hadoop");
c2.add("maven");
c2.add("hive");
c2.add("hbase");
c2.add("数据采集");
System.out.println("c1:"+c1);
System.out.println("c2:"+c2);
System.out.println("----------------------");
c1.addAll(c2);//将c2全部添加到c1里面
System.out.println("c1:"+c1);
System.out.println("------------------------");
c1.removeAll(c2);//把c1里面所有的c2的元素删除
System.out.println("c2:"+c2);
System.out.println("---------------------------");
System.out.println(c1.containsAll(c2));//判断c1是否完全包含c2
System.out.println("--------------------------");
c1.retainAll(c2);//求c1和c2的交集,结果在c1里面
System.out.println("c1:"+c1);
}
}
List 集合特有的方法
List集合中特有的成员方法(list集合有索引的概念,根据索引提供了一些特有的方法):
void add(int index,E element)----按指定索引的位置添加元素
E remove(int index)---按指定索引删除元素
E get(int index)---按指定索引获取元素
E set(int index,E element)---按索引修改元素(集合长度不变,会返回原来索引对应的值)
ListIterator listIterator()---list集合独有的迭代器(列表迭代器)
public class Demo1List {
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add("hello");
list1.add("world");
list1.add("banana");
list1.add("watermelon");
list1.add("mango");
System.out.println(list1);//存储有序
System.out.println("--------------------");
list1.add(2,"nice");
System.out.println(list1);
System.out.println("--------------------");
list1.remove(2);
System.out.println(list1);
System.out.println("--------------------");
System.out.println(list1.get(2));
System.out.println("---------------------");
list1.set(2, "dog");
System.out.println(list1);
System.out.println("----------------------------");
System.out.println("集合的长度是:"+list1.size());
System.out.println("----------------------------");
List 集合的遍历方式
使用 toArray()
方法
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
Object[] array = list.toArray();
for (Object obj : array) {
System.out.println(obj);
}
使用 Iterator
迭代器(接口)
Iterator使用方法
Iterator iterator() 迭代器,集合的专用遍历方式
Collection本身是不能遍历的,但是可以调用Collection中的方法生成一个可以遍历的迭代器,去遍历该迭代器
注意:在使用迭代器遍历时,若集合发生改变(如:向集合中添加元素),就会报错
如果想在遍历时作修改就只能对遍历器本身作相应的操作(迭代器改变,集合也会相应的发生变化)
而Integer迭代器是没有添加等操作的,只能使用ListInteger迭代器
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
List 集合存储自定义对象
存储自定义对象的步骤:
- 创建集合对象。
- 创建元素对象。
- 将元素添加到集合中。
- 遍历集合。
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
List<Student> students = new ArrayList<>();
students.add(new Student("Alice", 20));
students.add(new Student("Bob", 22));
for (Student student : students) {
System.out.println(student);
}
总结
List
接口及其实现类提供了灵活的元素存储和管理功能。选择哪种 List
实现类取决于具体的应用场景和性能要求。ArrayList
适合于需要快速访问元素的场景,Vector
适合于需要线程安全的场景,而 LinkedList
适合于需要频繁插入和删除元素的场景。通过理解 List
接口及其实现类的特点和使用方法,可以更有效地进行数据存储和管理。
到目前位置,我们学习过哪些可以存储元素的容器:
-
数组:
- 优点:不同的数组可以存储不同数据类型的元素。
- 缺点:长度不可变。
-
StringBuffer/StringBuilder:
- 优点:长度可以跟随元素的数量而改变。
- 缺点:里面的元素只有一种字符数据类型。
我们今后会根据元素的是否重复,存储和取出的顺序等来决定我们该使用什么样的容器来进行存储
如何遍历一个 Collection 集合
- 使用
toArray()
方法:把集合转成数组,可以实现集合的遍历。 - 使用
Iterator
接口:迭代器,集合的专用遍历方式。
注意:
在使用迭代器遍历时,若集合发生改变(如:向集合中添加元素),就会报错。如果想在遍历时作修改就只能对遍历器本身作相应的操作(迭代器改变,集合也会相应的发生变化),而 Integer
迭代器是没有添加等操作的,只能使用 ListIterator
,这是List集合特有的集合迭代器且只能用来遍历List集合且可以在正着遍历完集合的情况下倒着遍历集合。
Set 集合详解
在 Java 中,Set
是 Collection
接口的一个子接口,它表示一个元素无序、不重复的集合。Set
接口有两个主要的实现类:HashSet
和 TreeSet
。这些类提供了不同的性能特点和排序特性。
Set 接口的特点
- 元素无序:
Set
集合中的元素没有顺序。 - 元素唯一:
Set
集合不允许存储重复的元素。 - 没有索引:
Set
集合中的元素没有索引概念。
Set 接口的实现类
HashSet 类
- 底层数据结构:哈希表
- 特点:查找速度快,元素唯一,线程不安全,效率高。
- 使用场景:适用于需要快速查找和去重的场景。
HashSet 的 add 方法
HashSet
中的 add
方法实际上调用的是 HashMap
中的 put
方法。底层判断待插入的元素是否已经存在哈希表中的方式是:将待插入的元素的哈希值与已经存储在哈希表中元素哈希值进行比较,然后再调用待插入的元素的 equals
方法比较已经存储在哈希表中元素。若哈希值一样,且 equals
结果为 true
,就表示这两个元素是同一个元素,不做添加。
结论
若想要使用 HashSet
对元素进行去重,需要元素类型本身重写 hashCode
方法和 equals
方法。
TreeSet 类
- 底层数据结构:红黑树(自平衡二叉树)
- 特点:元素有序,线程不安全,效率相对较低。
- 使用场景:适用于需要有序集合的场景。
TreeSet 的排序方式
- 自然排序:元素类型实现
Comparable
接口,重写compareTo
方法。 - 比较器排序:在构造方法中传入实现了
Comparator
接口的对象,重写compare
方法。
TreeSet 的 add 方法
TreeSet
中的 add
方法实际上是调用了 TreeMap
中的 put
方法。
LinkedHashSet 类
- 底层数据结构:哈希表和双链表
- 特点:保证了元素的唯一性,同时维护元素的插入顺序,线程不安全,效率较高。
- 使用场景:适用于需要快速查找和保持插入顺序的场景。
Set 集合的常用方法
add(E e)
:向集合中添加元素。remove(Object o)
:从集合中移除元素。clear()
:清空集合。contains(Object o)
:检查集合是否包含某个元素。isEmpty()
:检查集合是否为空。size()
:获取集合中元素的数量。
示例代码
Set<Integer> numbers = new HashSet<>();
// 添加元素
numbers.add(1); // [1]
numbers.add(2); // [1, 2]
numbers.add(3); // [1, 2, 3]
// 检查集合是否包含某个元素
boolean contains = numbers.contains(2); // true
boolean containsNot = numbers.contains(4); // false
// 移除元素
numbers.remove(2); // [1, 3]
// 清空集合
numbers.clear(); // []
// 检查集合是否为空
boolean isEmpty = numbers.isEmpty(); // true
// 获取集合中元素的数量
int size = numbers.size(); // 0
Set 集合存储自定义对象
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 +
'}';
}
}
Set<Student> students = new TreeSet<>();
students.add(new Student("Alice", 20));
students.add(new Student("Bob", 22));
students.add(new Student("Charlie", 20));
for (Student student : students) {
System.out.println(student);
}
总结
Set
接口及其实现类提供了元素唯一和无序的集合存储功能。HashSet
适合于需要快速查找和去重的场景,而 TreeSet
适合于需要有序集合的场景。LinkedHashSet
结合了 HashSet
和 TreeSet
的特点,既保证了元素的唯一性,又维护了元素的插入顺序。通过理解 Set
接口及其实现类的特点和使用方法,可以更有效地进行数据存储和管理。