(所有源码均在:https://github.com/zongzhec/JavaPractise)
目录
集合概述
集合包含很多种容器,每种容器有不同的优缺点。
实际开发中,数据存储可能需要包含以下特点或组合:
1. 有序/无序
2. 可以重复/不能重复
3. 一对一/一对多
JDK在(1)数组,和(2)链式结构的基础上,设计出了很多的容器类型。主要有两大类:
1. Collection:一组对象。
2. Map:键值对
在本文中,我们会一一讨论Collection,List,以及Set的常用方法和注意事项。
常用方法主要包括:增、删、查、改,和遍历。
集合 Collection
Collection概述
java.util.Collection是层次结构中的根接口,把对容器的操作标准化,比如增删查改。
有一些Collection允许有重复的元素,而另一些则不允许。有一些Collection是有序的,而另一些无序。
因此JDK 不提供此接口的任何直接实现,而是提供更具体的子接口实现,如Set,List等。
Collection常用方法 (即:增删查改)
1. 添加
1.1. add(Object obj)
1.2. addAll(Collection other)
2. 删除
2.1. remove
2.2. removeAll(): 删除交集
2.3. clear(): 清空
3. 查询/遍历
跟借口中没有提供获取一个元素的方法。
3.1. toArray()
3.2. isEmpty()
3.3. foreach
4. 修改:
根接口中没提供set()方法
4.1. contains()
4.2. containsAll(): 判断other中的元素是否都在当前集合中。
5. 其他
5.1. retainAll(other): 保留交集
源码
package zongzhe.java_basic.data_structure.collection;
import java.util.ArrayList;
import java.util.Collection;
/**
* 用于理解Collection的常用方法。
*/
public class CollectionDemo {
public static void main(String[] args) {
checkAddFunctions(); // 添加
checkDeleteFunctions(); // 删除
checkIterateFunctions(); // 遍历
checkOtherFunctions(); // 其他
}
private static void checkAddFunctions() {
Collection c = new ArrayList(); // ArrayList是Collection子接口List的实现类。
c.add("1st element");
c.add("2nd element");
Collection other = new ArrayList();
other.add("3rd element");
other.add("4th element");
c.addAll(other);
System.out.println("c size: " + c.size());
}
private static void checkDeleteFunctions() {
Collection c = new ArrayList();
c.add("1st element");
c.add("2nd element");
Collection other = new ArrayList();
other.add("1st element");
other.add("4th element");
c.removeAll(other);
System.out.println("c size: " + c.size());
}
private static void checkIterateFunctions() {
Collection c = new ArrayList();
c.add("1st element");
c.add("2nd element");
for (Object obj : c) {
System.out.println(obj);
}
}
private static void checkOtherFunctions() {
Collection c = new ArrayList();
c.add("1st element");
c.add("2nd element");
Collection other = new ArrayList();
other.add("1st element");
other.add("4th element");
c.retainAll(other);
System.out.println("c size: " + c.size());
}
}
列表 List
List 概述
特征:有序,可重复
List 常用方法(增删查改+遍历)
1. 所有collection的常用方法,因为List继承了Collection
2. 额外的方法,大多跟index有关
2.1. 增: add(int index, E element), addAll(int index, Collection): 在指定位置插入一个或多个元素。
2.2. 删: remove(int index)
2.3. 查: get(int index), indexOf(Object o), lastIndexOf(Object o)
2.4. 改: set(int index, E element): 注意,原Collection根接口中没提供set()方法
2.5. 遍历:ListIterator,是Iterator的子接口,在其基础上增加了方向,同时增加了set和add方法。
源码
package zongzhe.java_basic.data_structure.collection;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListDemo {
public static void main(String[] args) {
checkAddFunctions(); // 增
checkRemoveFunc(); // 删
checkQueryFunc(); // 查
checkSetFunc(); // 改
checkIterFunc(); // 遍历
}
private static void checkAddFunctions() {
List list = new ArrayList();
list.add("one element");
list.add(0, "another element"); // 在指定位置添加元素
List list2 = new ArrayList();
list2.add("list2 element1");
list2.add("list2 element2");
list.addAll(1, list2); // 在指定位置添加集合,千万不要写成list.add(1, list2)
for (Object o : list) {
System.out.println("element: " + o);
}
}
private static void checkRemoveFunc() {
List list = new ArrayList();
list.add("one element");
list.add("another element");
list.remove(0);
for (Object o : list) {
System.out.println("element: " + o);
}
}
private static void checkSetFunc() {
List list = new ArrayList();
list.add("one element");
list.add("another element");
list.set(0, "updated element");
for (Object o : list) {
System.out.println("element: " + o);
}
}
private static void checkQueryFunc() {
List list = new ArrayList();
list.add("one element");
list.add("another element");
list.add("another element");
System.out.println("value of first index: " + list.get(0));
System.out.println("first index of another element: " + list.indexOf("another element"));
System.out.println("last index of another element: " + list.lastIndexOf("another element"));
}
private static void checkIterFunc() {
List list = new ArrayList();
list.add("one element");
list.add("another element");
list.add("third element");
ListIterator iter = list.listIterator();
// 往后遍历
while (iter.hasNext()) {
Object next = iter.next();
System.out.println(next);
}
// 往前遍历
iter = list.listIterator(list.size()); // 看到index,可以意识到我们其实可以从任意位置开始遍历
while (iter.hasPrevious()) {
Object prev = iter.previous();
System.out.println(prev);
}
}
}
List 常见的实现类
1. Vector:动态数组,旧版本,线程安全
2. ArrayList: 动态数组,新版本,线程不安全
3. LinkedList:双向列表、双端队列,内部实现是列表
4. Stack:栈,是Vector的子类,先进后出,已经不建议使用,因为其功能被LinkedList覆盖
push(压栈),pop(弹栈,移除栈顶元素),peek(返回栈顶元素,但不移除)
Set 集
Set 概述
不可重复的,无序的(不要拿LinkedHashSet抬杠)
如何保证两个元素不重复?——重写equals方法,而TreeSet是依据元素的“大小”顺序。
Set 常见实现
1. HashSet:完全无序
2. TreeSet:有大小顺序,和添加顺序无关(既然有“大小”顺序,那么就要求元素实现了Comparable)
3. LinkedHashSet:是HashSet的子类,但具备了“添加顺序”的功能。因此遍历时可以保证添加顺序,而存储和添加顺序无关,同时也导致效率比HashSet低。
Set 常用方法
基本是直接调用Collection的方法。但是在查重上有判断。换言之,如果你传入了自定义类型,则需要重写equals方法,来保证Set 不会加入重复元素。见如下代码。
源码
package zongzhe.java_basic.data_structure.collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
checkAddFunc(); // 增
checkCustomTypeAddFunc(); // 设定自定义类型,深入了解Set的功能
}
private static void checkAddFunc() {
Set set = new HashSet();
set.add("a"); // 此处是Collection的add方法
set.add("z");
set.add("2");
set.add("a");
set.add("b");
printSet(set); // 从打印结果看,没有顺序
Set treeSet = new TreeSet();
treeSet.add("a");
treeSet.add("z");
treeSet.add("c");
treeSet.add("a");
treeSet.add("b");
printSet(treeSet); // 从打印结果看,为按照字符顺序输出
}
private static void checkCustomTypeAddFunc() {
Set set = new HashSet();
set.add(new Person(1, 18, "person a")); // 添加自定义类型
set.add(new Person(2, 18, "person b"));
set.add(new Person(3, 18, "person c"));
set.add(new Person(4, 18, "person d"));
set.add(new Person(4, 18, "person d"));
printSet(set); // 从打印结果看,且仅有一个person d
Set treeSet = new TreeSet();
treeSet.add(new Person(1, 18, "person a")); // 添加自定义类型
treeSet.add(new Person(2, 18, "person b"));
treeSet.add(new Person(3, 18, "person c"));
treeSet.add(new Person(4, 18, "person d"));
treeSet.add(new Person(4, 18, "person e"));
printSet(treeSet); // 从打印结果看,Person按id排序,且person e 没有被添加进去
}
private static void printSet(Set set) {
System.out.println("printing set");
for (Object o : set) {
System.out.println(o);
}
}
}
class Person implements Comparable {
private int id;
private int age;
private String name;
public Person(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id &&
age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, age, name);
}
@Override
public int compareTo(Object o) {
Person person = (Person) o;
return this.id - person.id;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}