提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
一、集合概述
1.1、集合概念
1.首先,数组就是一个集合,集合就是一个容器,可以用来实现其他类型的数据
2.集合不能直接存储基本数据类型,另外集合也不能直接存储Java对象,集合当中存储的是Java对象的内存地址
3.在Java中每一个不同的集合,底层对应不同的数据结构,往不同的集合中存储元素,等于将数据放到了不同的数据结构当中
4.所有的Java集合类和集合接口都在java.util包下
1.2、集合继承结构
- 在Java中集合分为两大类
- 第一种是单个方式存储元素
- 单个方式存储元素,这一类的集合的顶级父类接口是:java.util.Collection
- 第二种是以键值对的方式存储元素
- 以键值对的方式存储元素,这一类集合的顶级父类接口是:java.util.Map
- 以键值对的方式存储元素,这一类集合的顶级父类接口是:java.util.Map
- 第一种是单个方式存储元素
1.3、集合底层数据结构概述
- ArrayList:底层是数组
- LinkedList:底层是双链表
- Vector:底层是数组,线程安全的,效率较低,使用较少
- HashSet:底层是HashMap,放到HashSet集合重的元素等同于放到HashMap集合key部分了
- TreeSet:底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合的key部分了
- HashMap:底层是哈希表
- HashTable:底层是哈希表,线程安全,效率较低,使用较少
- Properties:是线程安全的,并且key和value只能存储于字符串String
- TreeMap:底层是二叉树,TreeMap集合的key可以自动按照大小顺序排序
1.4、集合存储数据的特点
- List集合存储元素的特点:有序可重复(存进去的顺序与取出的顺序相同,每个元素都有下标)
- Set(Map)集合存储元素的特点:无需不可重复
- SortedSet(SortedMap)集合存储元素的特点:无序不可重复,但集合中的元素可排序
- Map集合的key就是一个Set集合,往Set集合里放数据,实际上放到了Map集合的key部分
二、Collection集合接口
2.1、Collection集合接口的常用方法
boolean add(E e)
确保此集合包含指定的元素(可选操作)。
//确保此集合包含指定的元素(可选操作)。
//boolean add(E e)
Collection<Object> c = new ArrayList<>();
c.add(3);
c.add(new Date());
c.add("hello"); //集合中实际上存储的是"hello"对象的内存地址
int size()
返回此集合中的元素数。
System.out.println(c.size());
void clear()
从此集合中删除所有元素(可选操作)。
c.clear();
System.out.println("集合中元素的个数:" + c.size());
boolean contains(Object o)
如果此集合包含指定的元素,则返回 true 。
boolean isRight = c.contains("XXX");
boolean remove(Object o)
从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
c.remove("hello");
boolean isEmpty()
如果此集合不包含元素,则返回 true 。
System.out.println(c.isEmpty());
Object[] toArray()
返回一个包含此集合中所有元素的数组。
c.add("abc");
c.add(100);
c.add("你好");
Object[] array = c.toArray();
Iterator<E> iterator()
返回此集合中的元素的迭代器。
迭代器Interface Iterator<E>中的常用方法:
1. boolean hasNext()
如果迭代具有更多元素,则返回 true 。
2. E next()
返回迭代中的下一个元素。
//以下迭代方式,是所有Collection通用的一种方式
//在Map集合中不能使用
//获取迭代器对象
Iterator<Department> iterator = deps.iterator();
while (iterator.hasNext()){
//存进去什么类型,取出来还是什么类型
Department dep = iterator.next();
//在输出的时候会转换为字符串,因为这里的println会调用toString()方法
System.out.println(dep);
- 注意:集合结构一旦发生改变,迭代器必须重新获取!
2.1.1、深入Contains()方法
//情景一
public static void main(String[] args) {
Collection<Object> c = new ArrayList<>();
//添加数据
String s1 = new String("abc");
c.add(s1);
String s2 = new String("opq");
c.add(s2);
String s3 = new String("abc");
//判断
boolean isContains = c.contains(s3);
System.out.println(isContains); //控制台会返回true
}
- 控制台会输出true,String类重写了equals()方法,所以之中比较的是值
- contains()方法是用来判断集合中是否包含某个元素的方法
- 它在底层调用了equals() 方法进行比较,equals()方法返回true就表示包含这个元素
//情景二
public static void main(String[] args) {
Collection<Object> c = new ArrayList<>();
//给集合添加数据
Person p1 = new Person("Ross");
c.add(p1);
Person p2 = new Person("Rose");
//判断
boolean isContains = c.contains(p2);
System.out.println(isContains); //如果不重写Person类的equals()方法,会返回false
}
- 没有重写Person类的equals()方法时,比较的时引用对象的地址,会返回false
- 重写了equals()方法以后会比较Person类中的name属性是否相同
- 在集合中尽量要重写equals()方法,否则调用的是Object类的equals()方法,比较的是引用对象的地址
2.1.2、深入remove()方法
public class CollectionTest04 {
public static void main(String[] args) {
Collection<Object> c = new ArrayList<>();
//给集合添加数据
Person p1 = new Person("Rose");
c.add(p1);
Person p2 = new Person("Rose");
//判断
c.remove(p2);
System.out.println(c.size()); //当我们重写了equals()方法时,这里会返回0
}
}
class Person{
private String name;
public Person(String name) {
this.name = name;
}
public Person() {
}
//重写equals()方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name);
}
}
2.1.3、关于集合中的删除
Iterator<Object> iterator = a.iterator();
while(iterator.hasNext()){
Object o = iterator.next();
iterator.remove(); //在迭代的过程中,只能使用迭代器的remove()方法,删除的是迭代器当前指向的元素,使用集合的remove()方法会报错!
// a.remove(100); //这么写会报错!
System.out.println(o);
三、List集合接口
- List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素
3.1、List接口的特有常用方法
1.void add(int index, E element)
将指定的元素插入此列表中的指定位置(该方法操作效率较低)。
List<Object> list = new ArrayList<>();
list.add(0, 20);
list.add(1,"老王");
list.add(2,"hello");
2.E get(int index)
返回此列表中指定位置的元素。
list.get(1);
- 因为有下标,所以list集合可以使用下标遍历
//因为有下标,所以list集合可以使用下标遍历!
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
3.indexOf(Object o)
返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
4.int lastIndexOf(Object o)
返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
5.E remove(int index)
删除该列表中指定位置的元素(可选操作)。
6.t<E> subList(int fromIndex, int toIndex)
返回此列表中指定的 fromIndex (含)和 toIndex之间的视图。
7.E set(int index, E element)
用指定的元素(可选操作)替换此列表中指定位置的元素。
四、ArrayList集合
4.1、ArrayList集合概述
1.ArrayList集合底层是数组结构;
2.ArrayList集合是线程不安全的;
3.ArrayList集合的初始化容量为10;
4.ArrayList集合会自动扩容,通过右移位运算,每次扩容原容量的1.5倍
5.由于ArrayList集合底层是数组,所以每次创建时尽量预估数组的初始化容量,减少数组的扩容,提高效率
6.ArrayList集合查询快,增删慢,但是在末尾增删数据还是很快的,由于底层是数组结构,无法找到一块巨大的连续存储的空间
4.2、ArrayList构造函数
1.ArrayList()
构造一个初始容量为10的空列表.(当添加第一个元素的时候才会初始化为10)
2.ArrayList(Collection<? extends E> c)
构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
3.ArrayList(int initialCapacity)
构造具有指定初始容量的空列表。
//初始化方法100
List list = new ArrayList(100);
//创建一个HashSet集合
Collection c = new HashSet();
c.add("1254");
c.add("500");
c.add("201");
//通过构造方法将HashSet集合转化为List集合
List list1 = new ArrayList(c);
for (Object o : list1) {
System.out.println(o);
五、LinkedList集合
5.1、有关链表的数据结构
1.对于链表数据结构来说:基本的单元是节点Node
2.对于单链表来说,任意一个节点Node中都有两个属性:
- 第一:存储的数据
- 第二:下一节点的内存地址
3.链表增删速度快,查询速度慢
5.2、LinkedList集合特点
1.LinkedList集合底层采用双向链表数据结构
2.对于链表数据结构来说,随机增删效率较高,检索效率较低
3.链表中的数据在空间存储上,内存地址是不连续的
六、Vector集合
1.Vector集合底层采用了数组结构
2.Vector集合底层是线程安全的
3.Vector所有的方法都有synchronized关键字修饰,所以线程安全,但是效率较低
4.初始默认容量为10,每次扩容时为原容量的一倍
- ArrayList集合转化为线程安全的集合
List<Object> list = new ArrayList();
list.add("aaa");
//将ArrayList集合转化为线程安全的
Collections.synchronizedList(list);
七、HashSet集合
1.HashSet是一个不允许有重复元素的无序集合
2.HashSet集合在创建的时候底层实际上new了一个HashMap集合,向HashSet集合中存放的元素实际上存储在HashMap集合中
3.HashSet集合的初始化容量为16,扩容之后是原容量的二倍
八、TreeSet集合
1.TreeSet集合实际上是TreeMap,创建TreeSet集合时实际上new了一个TreeMap
2.TreeSet集合是无序不可重复的,存储的元素可以自动按照大小排序
- 无序:指的是存进去的数据与取出来的顺序不同,并且没有下标