前言
首先要说这个集合框架,在Java中使用时特别重要而且具有一定的难度(涉及到数据结构),后期做项目时也是常用到的一个工具,各位可以上点心。
初识集合框架
了解集合框架
通常,我们的程序在程序运行时才能知道创建多少个对象。在程序未运行时,程序开发阶段,我们根本不知道到底需要多少数量的对象,甚至不知道它的准确类型。为了满足这些常规的编程需要,我们要求能在任何时候,任何地点创建任意数量的对象,而这些对象用什么来容纳呢?我们首先想到了数组,但是数组只能放统一类型的数据,而且其长度是固定的,那怎么办呢?集合便应运而生了!
因为Java是面向对象的一门语言所以集合框架也需要被实例化为对象,Java集合类存放于 java.util 包中,是一个用来存放对象的容器。使用之前需要导入。
那我们在什么时候应该用集合框架呢?
1.无法预测存储数据的数量
2.同时存储具有一对一关系的数据 (Map)
3.需要进行数据的增删改查
4.数据重复问题
集合框架有以下几点需要注意:
1.集合框架只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。
2.集合框架存放的是多个对象的引用,对象本身还是放在堆内存中。
3.集合框架可以存放不同类型,不限数量的数据类型。
如果不知道包装类大家可以去看看 Java常用工具类之包装类与字符串
集合框架与数组
乍一看,集合与数组十分相似,但其实不然,我们接下来看一下集合与数组的区别
集合中储存的是对象的引用
可见集合与数组之间不同之处还是很明显的!
集合框架分类
集合整体框架图是非常的复杂的,我们先来看看一张来自网络的图:
这对我们初学者来说十分不友好,对于我们初学者第一次也没有必要了解的太深,下面由我来进行总结吧!
Java 集合框架主要包括两种容器类型,一种是集合(Collection),主要用来储存一类元素的集合。另一种是图(Map),用来存储键值对映射。Collection 接口又有主要有 3 种接口,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、HashMap 等等。具体实现类不止这些但是我们先说这些当中最重要的几个。
集合框架实现顺序:
接口——>子接口——>抽象类(个别实现类才有)——>实现类
接口:是代表集合的抽象数据类型(未被实现)。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式(数据结构)操作集合对象
实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap
下面是它们的简单关系图:
下面就分别介绍一下吧!!!!
Collection
Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素,
Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。即Collection几乎是所有集合的祖先接口(个人理解)。
Collection 接口存储一组不唯一,无序的对象。
下面是Collection常用的一些方法:
boolean add(E e) //添加元素 e 到集合中 void clear() //清除集合中的所有元素 boolean isEmpty() //判断集合是否是空集合 boolean remove(Object e) //如果元素 e 出现在集合中,删除其中一个 int size() //返回集合中的元素个数 Object[] toArray() //返回一个装有所有集合中元素的数组
不是说接口不能被实例化吗?那我们怎么使用Collection的方法呢?
当然一个接口是无法被实例化的,但是我们已经学习过多态了啊,我们可以创建一个父类的引用指向子类的实例化,这样就可以使用它自身的方法了。如:
//创建一个整型的顺序表 Collection collection = new ArrayList<>(); //使用Collection中的add方法给表中添加数据8 collection.add(8)
这里要注意因为集合中只能存放对象,不能存放基本数据类型,所以我们这里使用的是int的包装类Integer类型来声明的。
List
List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为0,而且允许有相同的元素。
List 接口存储一组不唯一,有序(插入顺序)的对象。
List的常用方法:
//添加功能 boolean add(E e) //向集合中添加一个元素(尾部) void add(int index, E element) //在指定位置添加元素 boolean addAll(Collection c) //向集合中添加一个集合的元素,(只要继承于Collection的集合都可插入) //删除功能 void clear() //删除集合中的所有元素 E remove(int index) //根据指定索引删除元素,并把删除的元素返回 boolean remove(Object o) //从集合中删除指定的元素 boolean removeAll(Collection c) //从集合中删除一个指定的集合元素。 //修改功能 E set(int index, E element) //把指定索引位置的元素修改为指定的值,返回修改前的值。 //获取功能 E get(int index) //获取指定位置的元素 Iterator iterator() //就是用来获取集合中每一个元素。 //判断功能 boolean isEmpty() //判断集合是否为空。 boolean contains(Object o) //判断集合中是否存在指定的元素。 boolean containsAll(Collection c) //判断集合中是否存在指定的一个集合中的元素。 //长度功能 int size() //获取集合中的元素个数 //把集合转换成数组 Object[] toArray()
方法使用很简单,创建对象就可以直接引用了,与Collection类似,只不过增加了有序属性而已,就不演示了。。。
ArrayList
该类实现的是Collection接口的子接口List的接口,实现了可变大小的数组(动态),随机访问和遍历元素时,提供更好的性能。底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素。ArrayList 类位于 java.util 包中,使用前需要引入它。
ArrayList特点:
1.动态增长,以满足应用程序的需求
2.在列表尾部插入或删除非常有效
3.更适合查找和更新元素
4.ArrayList中的元素可以为null
ArrayList的构造方法:
ArrayList() //无参构造,这里没有指定顺序表容量,所以默认初始容量为10 ArrayList(Collection c) //利用其他 Collection 构建 ArrayList ArrayList(int initialCapacity) //指定顺序表初始容量
这里的Collection c是只要继承于Collection的集合都可插入。
具体的Collection c的理解大家可以去传送门看看。
至于它的其他方法都是从接口过来的,就不需要说了,下面也是一样实现类的方法就不举例子说明了。
LinkedList
该类实现的是Collection接口的子接口List和Queue接口。Queue这个结构我们后面在讲,今天不具体说。主要用于创建链表数据结构,查找效率低。LinkedList 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素。
1.与 ArrayList 一样,LinkedList 也按照索引位置排序,但它的元素之间是双向链接的
2.适合快速地插入和删除元素
3.LinkedList 实现 List 和 Queue 两个接口
4.LinkedList中允许有null(空)元素
LinkedList的构造方法:
LinkedList() //无参构造 LinkedList(Collection c) //利用其他 Collection 直接传入来构建 LinkedList
Set
Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。
Set 接口存储一组唯一,无序的对象。
Set与List都是继承于Collection的接口,那么Set与List有什么不同之处呢?总结如下:
Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变。
可以看出来他们有各自的优缺点,当我们在选择时候应该根据他们特点来选择适合我们当前需求的一种结构。
Set的常用方法:
//添加功能 boolean add(E e); boolean addAll(Collection c); //删除功能 boolean remove(Object o); boolean removeAll(Collection c); void clear(); //长度功能 int size(); //判断功能 boolean isEmpty(); boolean contains(Object o); boolean containsAll(Collection c); boolean retainAll(Collection c); //获取Set集合的迭代器: Iterator iterator(); //把集合转换成数组 Object[] toArray(); T[] toArray(T[] a); //判断元素是否重复,为子类提高重写方法 boolean equals(Object o); int hashCode();
HashSet
该类实现的是Collection接口的子接口Set的接口,不允许出现重复元素,不保证集合中元素的顺序。HashSet底层数据结构采用哈希表实现,元素无序且唯一,线程不安全,效率高,可以存储null元素,元素的唯一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的,如果没有重写这两个方法,则无法保证元素的唯一性。
HashSet是Set的一个重要实现类,称为哈希集
HashSet中的元素无序并且不可以重复
HashSet中只允许一个null元素
具有良好的存取和查找性能
至于关于重写hashCode()和equals()方法,保证元素唯一性这个比较繁琐而且比较重要,今天先简单了解一下,后面我们会对它们的方法以及重要的东西在来说一遍的。
Map
Map 接口存储一组键值对象,提供key(键)到value(值)的映射,与python中字典类似。
一般来说Map的key是不容许重复的,如果key重复了也不会报错,但是同一个 key 所对应的值只有一个,就是最后你更新这个 key 的值。这样的话对我们的数据处理不友好,所以我们在一个Map里面的key一般都是独一无二的。
下面是图(Map)常用的一些方法:
V get(Object k) //根据指定的 k 查找对应的 v V getOrDefault(Object k, V defaultValue) //根据指定的 k 查找对应的 v,没有找到就用默认值代替 V put(K key, V value) //将指定的 k-v 放入 Map boolean containsKey(Object key) //判断是否包含 key boolean containsValue(Object value) //判断是否包含 value Set> entrySet() //将所有的键值对返回 boolean isEmpty() //判断是否为空 int size() //返回键值对的数量 Map方法的使用与Collection也是类似的唯一不同之处就是声明类型的时候,需要声明两个类型,即:K—V。如下: //创建一个对象 Map map = new HashMap<>(); //向map中添加数据 map.put("白白",888);
其他方法也是类似的,就不一一演示了。
HashMap
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。该类实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。
1.基于哈希表的Map接口的实现
2.允许使用null值和null键
3.key值不允许重复
4.HashMap中的Entry对象是无序排列的
5.适用于Map中插入、删除和定位元素。
HashMap 的 key 与 value 类型可以相同也可以不同,可以是字符串(String)类型的 key 和 value,也可以是整型(Integer)的 key 和字符串(String)类型的 value。HashMap 类位于 java.util 包中,使用前需要引入它。
迭代器 Iterable
大家可能没有注意上面所有的集合类都实现了 Iterable 接口,那Iterable是什么玩意呢?
首先Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法
一般我们遍历一个集合可能用循环的方法实现,这是可以的,但是对于集合还有一种特殊的方法就是使用迭代器。迭代器是一个个具体对象,只不过它实现了 Iterator 接口和 ListIterator 接口。使用了迭代器,能够通过循环来得到或删除集合的元素。
其中Iterator 是 Java 迭代器最简单的实现,而ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口,ListIterator 继承了 Iterator,以允许双向遍历列表和修改元素,是Iterable的进化版。
迭代器的基本操作是 next 、hasNext 和 remove:
调用 next() 会返回迭代器的下一个元素,并且更新迭代器的状态。
调用 hasNext() 用于检测集合中是否还有元素。
调用 remove() 将迭代器返回的元素删除。
具体使用如下:
//注意需要导入包在使用 import java.util.ArrayList; import java.util.Iterator; public class Text_5 { public static void main(String[] args){ ArrayList arrayList = new ArrayList(); arrayList.add("白白牛!"); arrayList.add("白白帅!"); arrayList.add(1,"白白温柔!"); //注意这里原来arrayList是什么类型的这个迭代器<>中也是同步的 Iterator it = arrayList.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
输出为:
白白牛!
白白温柔!
白白帅!
这里需要注意顺序,是因为我arrayList.add(1,"白白温柔!");是指定位置加入的数据,所以白白温柔!在 白白帅!的前面。
其他方法用法也是类似的就不一一说明了。