当我们需要保存一组一样(类型相同)的元素的时候,我们应该使用一个容器
来存储,数组就是这样一个容器。
●
数组有什么缺点?
●
数组一旦定义,长度将不能再变化。
●
然而在我们的开发实践中,经常需要保存一些变长的数据集合,于是,我们需
要一些能够
动态增长长度的容器
来保存我们的数据。
●
而我们需要对数据的保存的逻辑可能各种各样,于是就有了各种各样的数据结
构。
Java中对于各种数据结构的实现,就是我们用到的集合。

第一部分主要讲解的是Collection部分,名为单列。
逻辑如图:

集合/容器
需要保存一组一样(类型相同)的元素
Collection(单列)
List:有序,可重复
ArrayList 存储方式为数组,可重复,按添加顺序排列
特点是查询比较快,可以直接用索引查询,但是删除和增加元素比较麻烦
(增加或者删除一个元素时,其他元素位置需要发生改变)
import java.util.ArrayList;
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
//ArrayList<Integer>arrayList = new ArrayList<>(10); 此时是在创建对象时就已经创建新数组
arrayList.add(10);//在添加第一个元素时创建新数组
arrayList.add(1, 0);//指定位置添加元素 后面的元素要往后移动一位
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
arrayList.add(6);
arrayList.add(7);
arrayList.add(8);
arrayList.add(9);
arrayList.add(9);
//会自动扩容 为原来长度的1.5倍
arrayList.size();//容量
arrayList.contains(100);//是否包含一百这个元素,返回值为true或false
arrayList.clear();//清除
arrayList.set(3, 9);//在指定位置替换某个元素
System.out.println(arrayList);
}
}
通常遍历元素的话有三种方式,我都会写在下方的代码中:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class ArrayListDemo1 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
/*
遍历的方法
*/
/*
1.for循环 遍历
可以区间遍历
*/
/*for (int i = 0;i<arrayList.size();i++){
//System.out.println(arrayList.get(i)); //直接遍历
//删除元素
if (arrayList.get(i).equals("a")){
arrayList.remove(i);
i--;//如果直接继续循环那遇到重复出现要删除的元素就不能完全删除
//但是如此需要对索引掌握到位,不然就会出现错误
}
}*/
/*
2.增强for循环 遍历
方便,但是只能全部遍历
*/
/* for(String s : arrayList) {
System.out.println(s);
//上方是遍历
*/
/*
//下方是删除元素
if (s.equals("a")){
arrayList.remove(s);
}
//无法通过该方式进行遍历修改元素,程序抛出异常
*//*
}*/
/*
3.迭代器遍历
*/
/* Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext()){
String s = iterator.next();
//System.out.println(s);
if (s.equals("a")) {
//此处不能使用list.remove(s); 因为一直在迭代器中操作,不能直接对arraylist操作
iterator.remove();
}
}*/
/* ListIterator<String> iterator1 = arrayList.listIterator();
while (iterator1.hasNext()){
String s = iterator1.next();
if (s.equals("a")) {
iterator1.remove();
}
}*/
ListIterator<String> iterator1 = arrayList.listIterator(arrayList.size());
while (iterator1.hasPrevious()){
String s = iterator1.previous();
if (s.equals("a")) {
iterator1.remove();
}
System.out.println(s);
}
System.out.println(arrayList);
}
}
LinkedList 存储方式为链表,可重复,按添加顺序排列
特点是查询比较慢(需要从头节点或者尾节点开始逐个查询)
但是增加或者删除元素比较方便
【具体解释请参照数据结构相关知识】
LinkedList与ArrayList用法差不多,需要注意的是LinkedList底层实现是链表,所以虽然方法名相同,但是底层实现代码不同
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("a");
linkedList.add("b");
linkedList.add("c");
linkedList.add("d");
linkedList.add("e");
linkedList.add("f");
linkedList.add("g");
linkedList.remove();//检索并删除此列表第一位
linkedList.removeLast();//删除最后一位
linkedList.size();
linkedList.get(3);
System.out.println(linkedList);
}
}
Vector 线程安全,存储方式也是数组,一般用于多线程
import java.util.Vector;
public class VectorDemo {
/*
线程安全,底层也是数组实现
synchronized 同步锁
*/
public static void main(String[] args) {
Vector<String> vector = new Vector<>();
vector.add("a");
vector.add("b");
vector.add("c");
vector.add("d");
vector.add("e");
vector.add("f");
System.out.println(vector.size());
vector.set(4, "z");
System.out.println(vector.contains("c"));
vector.remove("b");
System.out.println(vector);
}
}
Set:无序,不可重复
HashSet:元素不能重复,
Set接口实现类的共同特征:不能存储重复元素 HashSet:无序的(值的哈希码%数组长度【取余】) TreeSet:有序的(排序)
//注意,下方有三部分代码,如果要复制,需要单独分开
import java.util.HashSet;
public class HashSetDemo1 {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("a");
hashSet.add("x");
hashSet.add("y");
hashSet.add("d");
hashSet.add("e");
System.out.println(hashSet);
}
}
import java.util.HashSet;
public class HashSetDemo2 {
/*
HashSet/HasMap中如何保证值(键)不重复:
当添加一个元素时,首先会调用值的hashCode方法,计算出一个hash值
但是!哈希值不安全,有可能内容不同,但是hash值相同,所以还要调用equals()方法,比较内容一致与否
如果不先调用hashCode方法,那只调用equals方法会造成比较的效率低下,所以先调用hashCode方法
*/
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("a");
hashSet.add(new String("入地"));//哈希值一样,那就会开始调用equals()方法比较内容
hashSet.add(new String("上天"));//哪怕new一个新对象,hashSet方法中也默认重写了equals()方法和hashCode()方法,不比较地址
hashSet.add("d");
hashSet.add("e");
System.out.println(hashSet);
}
}
import java.util.HashSet;
public class HashSetDemo3 {
public static void main(String[] args) {
HashSet<Car> hashSet = new HashSet<>();
Car car1 = new Car(101, "奔驰1");
Car car2 = new Car(101, "奔驰1");
Car car3 = new Car(103, "奔驰3");
Car car4 = new Car(104, "奔驰4");
Car car5 = new Car(105, "奔驰5");
hashSet.add(car1);
hashSet.add(car2);
hashSet.add(car3);
hashSet.add(car4);
hashSet.add(car5);
System.out.println(hashSet);
//只有四个元素,因为Car类中重写了equals() hashCode()方法,先用哈希值比较,若相同再使用euqals()方法比较,
//若没有重写,那根据Object中hashCode()方法,使用他们的地址比较,这是两个对象,必然有两个不同的地址,此时会有5个元素
}
}
//上下两处都要用到自定义的Car类
public class Car implements Comparable<Car>{
private int num;
private String name;
public Car(int num, String name) {
this.num = num;
this.name = name;
}
@Override
//必须定义类时重写hashCode()方法,不然默认调用父类Object中的hashCode方法,比较的是地址,而不是内容
public int hashCode() {
int result = num;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Car{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
if (num != car.num) return false;
return name != null ? name.equals(car.name) : car.name == null;
}
@Override
//TreeSet中比较的方法 需要有参考的参数
public int compareTo(Car o) {
return this.num-o.num;
}
}
TreeSet:元素不能重复,但是是有序的(由排序得来)
import java.util.TreeSet;
public class TreeSetDemo1 {
/*
TreeSet 不可重复,有序的(可以排序)
*/
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<>();
set.add("a");
set.add("d");
set.add("f");
set.add("e");
set.add("c");
System.out.println(set);
}
}
import java.util.TreeSet;
public class TreeSetDemo2 {
/*
TreeSet 不可重复,有序的(可以排序)
*/
public static void main(String[] args) {
TreeSet<Car> set = new TreeSet<>();
Car car1 = new Car(101, "奔驰1");
Car car2 = new Car(101, "奔驰1");
Car car3 = new Car(103, "奔驰3");
Car car4 = new Car(104, "奔驰4");
Car car5 = new Car(105, "奔驰5");
set.add(car1);
set.add(car3);
set.add(car5);
set.add(car4);
set.add(car2);
System.out.println(set);
}
}
Set遍历只能用增强for循环和iterator(迭代器)。
因为Set里没有索引,所以不能用for循环
Map:(双列)
HashMap:使用哈希表
HashTable:
TreeMap:使用树结构