目录
一、集合
1、集合的概述
1、是什么
2、能做什么
3、能作用在哪儿
集合的概念:集合是一个批量存储的容器【程序=数据结构+运算方法】
数据结构:研究大批量数据在内存中的存储形式,存的越好将来取得越方便越高效
常见的数据结构:线性表 链表 哈希表 二叉树 红黑树......
2、集合的体系
所有的集合相关的接口和类都是定义在Java.util包中
·集合容器包括单列集合和双列集合
单列集合:集合中每个元素只能存储一个值。顶级接口为Collection,该接口定义了很多集合对应的操作方法规范。其中单列集合又包括了List和Set集合。
·List接口:有序可重复,且存入顺序和输出顺序一致,每个元素都有一个对应的下标。包括三个实现类:ArrayList、Vector采用底层采用数组 LinkedList底层采用双向数据链表。
·Set接口:无需不可重复,因此可以利用Set接口进行去重。包括两个实现类:HashSet底层采用哈希表,TreeSet采用的是红黑树。
双列结合:集合的每个元素由两个值组成且不可分,分别为key和value要求对于一个双列集合来说每个元素的key都必须是唯一的且不可重复,key和value之间存在映射关系,因此也称键值对集合。顶级接口为Map。包括三个实现类:HashMap、Hashtable底层采用哈希表,TreeMap底层采用红黑树。
3、Collection接口
Collection接口的常用方法:
·size():获取集合中的元素的个数。
·add(Object o):添加元素
·addAll():批量元素的添加
·isEmpty():判断集合是否为空
·toArray():将集合转换成数组
·contains():判断集合中是否包含指定元素,返回布尔值。
·iterator():用来进行集合中的元素的遍历
·clear():清空集合 size=0
Iterable定义了一个方法规范:Iterator iterator(); 该方法的特点:无参且返回一个Iterator类型的对象,这个对象称为迭代器对象
迭代器对象提供了两个方法:next():得到集合的下个元素并返回,hasNext()判断是否还有下一个元素,并返回一个boolean值。
//集合的迭代步骤
//1.调用集合对象的iterator()方法获取迭代器对象
Iterator iterator = collection.iterator();
//2.调用next方法不断地获取下一个元素地值,并结合hasNext方法判断是否存在下一个元素
while(iterator.hasNext()){
Object value = iterator.next();
System.out.println(value);
}
foreach 增强for循环,对于集合的遍历简化了迭代器的编写
语法
for(变量:集合){
//通过变量直接获取集合中的每个元素
}
·remove(Object o):从集合中删除指定的元素 remove方法删除比较根据equals()方法,但是只能删除第一个符合条件的元素
for (int index = 0; index < size; index++){
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
如果想要删除所有符合条件的语句则:
while(iterator.hasNext()) {
Object element = iterator.next();
//如果一个常量和一个变量进行equals比较建议将常量写前面
if("张三".equals(element)) {
//删除这个元素
//collection.remove(element);
//collection.add("111");
//迭代的过程中不能直接对集合进行新增和删除操作
//需要使用迭代器自己的remove方法
iterator.remove();//将当前正在迭代的元素删除
}
}
4、List接口
List接口继承了Collection父接口,并在父接口的基础上又扩展了一些新的方法规范
特点:有序可重复
List接口的展方法使用
·get(int index):根据提供的下标获取对应的元素值
·set(int index,Object value):将指定下标位置的元素修改为对应的值
·indexOf():获取元素最后出现的下标
·循环遍历:List集合的遍历有三种:1.使用迭代器 2.使用foreach 3.使用简单的for循环
·remove(int index):根据下标删除指定位置的元素
5、List接口的常用实现类
5.1、ArrayList
ArrayList是Java语言中的一个类,它是一个动态数组,具有可变长度的特点。ArrayList可以存储任意类型的对象,包括基本数据类型的包装类,例如Integer、Double、Boolean等等。
以下是ArrayList常见使用方法
1、创建ArrayList对象
ArrayList<String> list = new ArrayList<>();
2、添加元素
list.add("apple");
list.add("banana");
list.add("orange");
3、获取元素
String fruit = list.get(0);
4、修改元素
list.set(0, "watermelon");
5、删除元素
list.remove(0);
6、获取元素的数量
int size = list.size();
7、遍历ArrayList
for (String fruit : list) {
System.out.println(fruit);
}
需要注意的是,ArrayList 在内存占用上会比固定长度数组占用更多一些,因为 ArrayList 内置了修改数组长度的功能,这也是它灵活性的体现。
当 ArrayList 中的元素个数超出了其内部数组的容量时,它会自动增加容量,从而实现自动扩容。具体扩容方式如下:
1.初始化时,ArrayList 会创建一个初始容量为 10 的内部数组。
2.当添加元素时,如果当前元素个数等于内部数组的容量时,ArrayList 会创建一个新的容量为“旧容量 x 1.5 + 1”的新数组,将旧数组中的元素全部复制到新数组中,并将新元素添加到新数组的末尾。
比如,在初始容量为10的情况下,当添加第11个元素时,ArrayList 会创建一个新的容量为“10 x 1.5 + 1 = 16”个的新数组,并将旧数组中的10个元素全部复制到新数组中。然后,再将第11个元素添加到新数组的末尾。
需要注意的是,ArrayList 在扩容时会涉及到创建新数组、复制元素等操作,因此会对性能产生一定的影响。因此,如果已知数据量较大,可以在创建 ArrayList 对象时,直接将初始容量设置为比较大的值,以减少自动扩容的次数。例如:
ArrayList<String> list = new ArrayList<>(1000);
这样,在初始化时就会创建一个容量为1000的内部数组,避免了多次自动扩容的开销。
5.2、LinkedList
ArrayList底层采用的是数组,数组在内存中是连续的空间。
LinkedList采用的是双向数据链表,链表中每个元素对应的空间是不连续的。
链表中的每个元素由三部分组成
//链表中的每个元素就是一个Node类型的对象
private static class Node<E> {
//当前节点的数据
E item;
//下一个节点的地址
Node<E> next;
//上一个节点的地址
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
可以用来存储和操作链表数据结构。LinkedList 每个节点都包含一个数据元素和两个指针,用于指向链表中前一个节点和后一个节点。
以下是 LinkedList 的常见使用方法:
1.创建 LinkedList 对象
LinkedList<String> list = new LinkedList<>();
2.添加元素
list.add("element 1");
list.addFirst("element 0");
list.addLast("element 2");
3.获取元素
String firstElement = list.getFirst();
String lastElement = list.getLast();
String elementAtIndex = list.get(1);
4.修改元素
list.set(1, "modified element");
5.删除元素
list.removeLast();
list.removeFirst();
list.remove("element");
6.获取元素数量
int size = list.size();
7.遍历 LinkedList
for (String element : list) {
System.out.println(element);
}
需要注意的是,相较于 ArrayList,LinkedList 在增删操作上具有更好的灵活度,因为它可以通过修改链表节点之间的指针,来快速进行元素的添加、删除操作。同时,在查询操作上,由于链表随机获取一个元素的时间复杂度为 O(n),因此其性能可能不如 ArrayList。因此,在选择使用 LinkedList 和 ArrayList 时,需要仔细权衡其特点。
5.3、Vector【已淘汰】
需要注意的是,Vector 具有线程安全的特性,因此在多线程场景下可以保证元素的修改和访问的安全性。但是,由于要保证线程安全,Vector 在性能上不如 ArrayList。所以在没有多线程安全需求的情况下,建议使用 ArrayList。尽管如此,在某些特定场景下仍然会有使用 Vector 的需求,比如需要在多线程环境中进行高频率的读写操作。