1、集合概述
什么是集合?集合有什么用?
- 数组其实就是一个集合,集合实际上是一个容器,它可以容纳其他类型的数据,集合为什么在开发中使用最多?
- 集合是一个容器,是一个载体,可以容纳多个对象,在实际开发中,假设连接数据库,数据库种有10条记录,那么假设把10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个对象放在一个集合中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来
- 集合不能存储基本数据类型,也不能存储java对象,集合当中存储的都是java对象的内存地址,(或者说集合中存储的是引用),集合在java中本身是一个对象,集合中任何时候存储的都是引用
- java中每一个不同的集合,底层会对应的不同的数据结构,往不同的集合中存储元素,等于将数据放到了不同的数据结构中去,什么是数据结构?数据存储的结构就是数据结构,不同的数据结构,数据存储方式不同,例如:
- 数组其实就是一个集合,集合实际上是一个容器,它可以容纳其他类型的数据,集合为什么在开发中使用最多?
java.util.*
4.3 总结
- ArrayList: 底层是数组
- LinkedList: 底层双向列表
- Vector: 底层是数组,线程安全的,效率低,使用较少
- HashSet: 底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了
- TreeSet: 底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了
- HashMap: 底层是哈希表
- Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少
- Properties: 线程安全,key和value只能存储字符串String
- TreeMap: 底层是二叉树,TreeMap中的key可以按照自动大小排序
4.4 特点
5、collection
5.1 集合中通用方法
```python package com.collection;
import com.oop.Student;
import java.util.ArrayList; import java.util.Collection;
/ java.util.collection 中常用的方法 1、Collection 中能存放什么元素 没有使用泛型之前,Collection中可以存储object所有子类型 使用了泛型之后,Collection只能存储某个具体类型 Collection中什么都能存,只能是object的子类就行 集合中不能直接存储基本数据类型,不能存储java对象,只是存储java对象的内存地址 / public class Demo01 { public static void main(String[] args) { // 1、创建一个对象 // Collection collection = new Collection(); 接口是抽象的,无法实例化 Collection c = new ArrayList(); c.add(100);// 实际放进去一个对象的内存地址,Integer x = new Integer() c.add(new Student1());// 自动装箱
//2、获取集合中元素个数
System.out.println("集合中的元素个数:"+c.size());
// 3、判断集合中是否包含元素
System.out.println("集合中是否包含元素100:"+c.contains(100));
// 4、移除元素
c.remove(100);
System.out.println("集合中是否包含元素100:"+c.contains(100));
// 5、isEmpty()
System.out.println("集合中元素是否为空:" + c.isEmpty());
// 6、元素清空 clear
// 7、将集合转为数组
Object[] objs = c.toArray();
for(int i = 0; i < objs.length; i++){
Object o = objs[i];
System.out.println(o);
}
}
}
class Student1{
}
<a name="RN0gk"></a>
#### 5.2 关于集合中遍历|迭代专题(重点 *****)
```python
package com.collection;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
/*
关于集合中遍历|迭代专题(重点 *****)
*/
public class Demo02 {
public static void main(String[] args) {
// 以下讲解的是通用的迭代、遍历方式
// Map中不能用,在所有的collection以及子类中使用
//创建集合对象
Collection c = new HashSet();
c.add("abc");
c.add(100);
c.add(true);
c.add(3.14);
Iterator iterator = c.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println("迭代元素: " + obj);
}
// 迭代元素: abc
// 迭代元素: 100
// 迭代元素: 3.14
// 迭代元素: true
}
}
5.3 Collection集合的contains方法
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
/*
Collection集合的 contains方法
contains方法是判断集合中是否包含某个元素的方法
调用了equals方法进行比对
equals方法返回true则包含
*/
public class Demo03 {
public static void main(String[] args) {
Collection c = new ArrayList();
String s1 = new String("abc");
c.add(s1);
String s2 = new String("def");
c.add(s2);
System.out.println(c.size());//2
String x = new String("abc");
System.out.println(c.contains(x));//true String类的equals方法重写了比较内容
}
}
5.5 存放在集合中的类型要重写equals方法
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
public class Demo04 {
public static void main(String[] args) {
Collection c = new ArrayList();
User u1 = new User("jack");
User u2 = new User("jack");
c.add(u1);
System.out.println(c.contains(u2)); // 为重写equals方法 返回false
}
}
class User{
private String name;
public User() {}
public User(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof User)) return false;
if (obj == this) return true;
User u = (User)obj;
return u.name.equals(this.name);
}
}
5.6 remove方法
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
public class Demo05 {
public static void main(String[] args) {
Collection c = new ArrayList();
String s1 = new String("abc");
c.add(s1);
String s2 = new String("abc");
c.remove(s2);
System.out.println(c.contains(s1));//false, remove重写了equals方法,删除了内容abc
}
}
5.7 集合结构发生改变,迭代器需要重新获取
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
集合结构发生改变时,迭代器必须重新获取,否则发生异常,Java.util.ConcurrentModifycationException
编写代码时,next()方法返回值类型必须时Object
iterator.remove();// 0 迭代器删除的一定是当前元素
*/
public class Demo06 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("abc");
c.add("def");
Iterator iterator = c.iterator();
while (iterator.hasNext()){
Object o = iterator.next();
// c.remove(o);
System.out.println(o);
System.out.println(iterator.hasNext());
iterator.remove();// 0 迭代器删除的一定是当前元素
}
System.out.println(c.size());
}
}
6、List特有方法
package com.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
1、List集合存储元素特点
有序:List集合中的元素有下标
从0开始,以1递增
可重复,存储1一个1,还可存储1
2、List既可以是Collection接口的子接口,那么List肯定有自己的特色方法
以下是List方法特有的方法
void add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
E get(int index) 返回此列表中指定位置的元素。
int indexOf(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
E remove(int index) 删除该列表中指定位置的元素(可选操作)。
int lastIndexOf(Object o) 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
E remove(int index) 删除该列表中指定位置的元素(可选操作)。
E set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。
*/
public class Demo07 {
public static void main(String[] args) {
List myList = new ArrayList();
//添加元素,默认向元素末尾添加元素
myList.add("abc");
myList.add("def");
myList.add(1,100);
System.out.println(myList.lastIndexOf(100));
// 通过下表获取元素
Object obj1 = myList.get(1);
System.out.println(obj1);
Iterator c = myList.iterator();
while(c.hasNext()){
Object obj = c.next();
System.out.println(obj);
}
}
}
6.1 ArrayList
- ArrayList集合初始化容量是10
- 集合底层是object[] 数组
- 使用的哪个集合最多? ```python package com.collection;
/ ArrayList 集合 1、默认初始化容量是10 2、集合底层是object数组 3、构造方法 new ArrayList() new ArrayList(20) 4、ArrayList集合内容 增长到原来的1.5倍 ArrayList集合底层是数组,怎么优化? 尽可能少的内容,因为数组扩容效率比较低,建议使用ArrayList集合 的时候预估元素的个数,给定一个初始化容量 5、数组优点 检索效率比较高,每个元素占用空间大小相同,内存地址连续,知道首元素内存地址,然后知道下标, 通过数据表达式就能计算元素的内存地址,所以检索效率高。 缺点 随机增删元素的效率比较低 6、向数组末尾添加元素 随机增删元素效率比较低 7、向数组末尾添加元素,效率很高,不受影响 8、面试官经常问的问题? 这么多的集合中,你用的哪个集合最多? ArrayList 因为往数组末尾添加元素,效率不受影响 另外,我们检索或查找某个元素的操作比较多 / public class Demo08 { public static void main(String[] args) { / ArrayList(Collection<? extends E> c) 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。 / Collection c = new ArrayList();
c.add(100);
c.add("abc");
List c1 = new ArrayList(c);
for(int i = 0; i < c1.size(); i ++){
Object o = c1.get(i);
System.out.println(o);
}
}
}
<a name="ZsVF4"></a>
### 7、链表的数据结构
<a name="UlQZW"></a>
#### 7.1 概念
- 基本单元-节点
- 有两个属性,data(存储的数据),next(下一节点的内存地址)
- 优点
- 增删效率高,不涉及大量元素位移问题
- 缺点
- 查询效率低,每一次查询某个元素的时候需要从头节点开始往下遍历
![image.png](https://cdn.nlark.com/yuque/0/2021/png/12881754/1625403632521-0f6b68ac-27e8-4287-874e-812d677c954a.png#clientId=u8c153e9d-933d-4&from=paste&height=354&id=u399cd7e6&margin=%5Bobject%20Object%5D&name=image.png&originHeight=707&originWidth=1405&originalType=binary&ratio=1&size=467000&status=done&style=none&taskId=u677da7cb-6710-423e-8d7d-be334397e9b&width=702.5)
<a name="K5Nhv"></a>
#### 7.2 单链表实现
```python
// client
package com.danlink;
public class Link {
// 定义头节点
Node header = null;
int size = 0;
/*
查找集合最后一个元素
*/
public Node findLastNode(Node node){
if (node.next == null){
return node;
}
return findLastNode(node.next);
}
/*
查找某个元素
*/
// 返回元素个数
public int size(){
return size;
}
// 添加链表中某个数据
public void add(Object data){
if (header == null){
header = new Node(data,null);
}else{
Node lasNnode = findLastNode(header);
lasNnode.next = new Node(data,null);
}
size += 1;
}
// 删除
public void remove(Object obj){
}
// 修改
public void modify(Object obj){
}
// 查询
public void find(Object obj){
}
}
// Node
package com.danlink;
/*
单链表中的节点
节点是单链表的基本单元
每一个节点Node都有两个属性
一个属性:是存储的数据
另一个属性:是下一个节点的内存地址
*/
public class Node {
// 存储的数据
Object data;
// 下一个节点的地址
Node next;
public Node() {}
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
}
// link
package com.danlink;
public class Link {
// 定义头节点
Node header = null;
int size = 0;
/*
查找集合最后一个元素
*/
public Node findLastNode(Node node){
if (node.next == null){
return node;
}
return findLastNode(node.next);
}
/*
查找某个元素
*/
// 返回元素个数
public int size(){
return size;
}
// 添加链表中某个数据
public void add(Object data){
if (header == null){
header = new Node(data,null);
}else{
Node lasNnode = findLastNode(header);
lasNnode.next = new Node(data,null);
}
size += 1;
}
// 删除
public void remove(Object obj){
}
// 修改
public void modify(Object obj){
}
// 查询
public void find(Object obj){
}
}
7.3 链表的优点和缺点
- 链表的优点
- 链表的元素在空间存储上内存地址不连续
- 随机增删元素的时候不会有大量元素位移,因此随机增删效率高,建议在随机增删的业务场景较多时使用LinkedList
- 链表的缺点
- 不能通过数学表达式计算查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止,所以linkedList集合索引/查找的效率较低
- ArrayList:把检索发挥到极致,末尾添加元素效率很高,索引效率高不是因为下标的原因,是因为底层数组发挥的作用,linkedList同样有下标,只能从头节点一个一个遍历
- LinkedList:把随机增删发挥到极致,
-
7.4 末尾添加元素效率为什么高?
-
7.5 LinkedList 源码分析(双向链表)
7.6 分析
package kyrie.bao.com.collection;
import java.util.LinkedList;
import java.util.List;
public class Demo01 {
public static void main(String[] args) {
List list = new LinkedList();
list.add("a");
list.add("b");
list.add("c");
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
System.out.println(obj);
}
}
}
7.7 Vextor
非线程安全变成线程安全的
List mylist = new ArrayList();
Collection.syschronizedList(mylist);
mylist.add("a");
mylist.add("b")