Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
- 接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
- 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
- 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序,这些算法实现了多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
集合概述:类似数组的容器,只能存储引用数据类型
优点:可扩展,可以调用多种方法,存储全是引用数据类型及对象,利于面向对象编程
集合中分单列集合和双列集合:
- Collection是单列集合,Collection是一个接口,List接口和Set接口继承了Collection接口,ArrayList和LinkedList和Vector实现了List接口,HashSet和LinkedListSet实现了Set接口
- Map是双列集合,Map是一个接口,HashMap和LinkedHashMap实现了Map接口
Collection单列集合
List是线性列表的存储方式,长度可动态改变
List接口是一个有序的Collection,使用此接口可以精确的控制每个元素的插入位置,能够通过索引来访问List中的元素,第一个索引为0,可以存在相同的元素
List接口存储一组,不唯一,有序的对象
Set接口具有与Collection完全一样的接口,Set不保存重复的元素
Set接口存储一组,唯一,无序的对象
1.1. Set集合和List集合的区别
- . Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
- 2. Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
- 3. List 和数组类似,可以动态增长,根据实际存储的数据的长度自动增长 List 的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。
1.2. Collection集合的通用遍历方式
- 迭代器遍历:直接从集合中获取iterator()方法,返回一个迭代器对象
- hasNext()判断是否有下一个可以迭代的元素
- next()获取集合中的下一个元素
- remove()删除集合中迭代器正在遍历的元素
Map双列集合
使用key->value对的存储方式,长度可以动态改变
Map 接口存储一组键值对象,提供key(键)到value(值)的映射。
Map.Entry:描述在一个Map中的一个元素(键值对),是一个Map的内部接口
HashMap特点:元素无序,允许为空,key不能重复
List接口
List接口是Collection的子接口
List特点:有序,可重复
List中存在索引,所以可以通过索引获取List中的元素
1.1. 特有方法
List中的特有方法
add(int index,Object obj) 将指定元素插入到集合的指定位置
remove(index)删除指定索引上的元素
set(int index ,Object obj) 用指定元素替换到指定索引上原有的值
1.2. List中的特有遍历方式
通过size获取数组的长度,再通过get方法获取每个索引上对应的元素
1.3. List中的异常
ConcurrentModificationExecption:并发修改异常
避免方式:集合遍历集合修改,迭代器遍历迭代器修改
List的实现类
List是一个接口,无法直接创建对象,所以根据底层实现不同,具有不同实现类
ArrayList:数组实现,顺序存储
LinkedList:链表实现,节点存储
ArrayList
ArrayList类是一个可以动态修改的数组
ArrayList继承了AbstractList,实现了List接口
ArrayLIst查询效率高,增删效率低
import java.util.ArrayList; // 引入 ArrayList 类
ArrayList<E> objectName =new ArrayList<>(); // 初始化
- E:泛型数据类型,用于设置objectName的数据类型,只能是引用数据类型
- objectName:对象名
ArrayList 是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
在ArrayList中添加元素可以用add方法
在ArrayList中访问元素可以用get方法
在ArrayList中修改元素可以用set方法
在ArrayList中删除元素可以用remove方法
遍历数组
import java.util.ArrayList;
public class RunoobTest {
public static void main(String[] args) {
ArrayList<String> sites = new ArrayList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Weibo");
for (int i = 0; i < sites.size(); i++) {
System.out.println(sites.get(i));
}
}
}
import java.util.ArrayList;
public class RunoobTest {
public static void main(String[] args) {
ArrayList<String> sites = new ArrayList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Weibo");
for (String i : sites) {
System.out.println(i);
}
}
}
LinkedList
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。
链表可分为单向链表和双向链表。
一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接。
LinkedList:以节点实现,链式存储
LinkedList的查询速度慢,增删速度块
LinkedList的底层是双向链表,双向链表中存储了上一个节点的地址值,下一个节点的地址值,本节点的值
以下情况需要用到LinkedList
- 你需要通过循环迭代来访问列表中的某些元素。
- 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
LinkedList 继承了 AbstractSequentialList 类。
LinkedList 实现了 Queue 接口,可作为队列使用。
LinkedList 实现了 List 接口,可进行列表的相关操作。
LinkedList 实现了 Deque 接口,可作为队列使用。
LinkedList 实现了 Cloneable 接口,可实现克隆。
LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
// 引入 LinkedList 类
import java.util.LinkedList;
LinkedList<E> list = new LinkedList<E>(); // 普通创建方法
或者
LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表
因为LinkedList在增删元素方面很便捷,所以给LinkedList中提供了一些增删的方法
addFirst()将指定元素插入到列表头部
addLast()将指定元素插入到列表尾部
removeFirst()删除头部元素并返回
removeLast()删除尾部元素并返回
getFirst()返回头部元素
getLast()返回尾部元素
泛型
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
泛型类
带有泛型的类
格式:
class 类名 <泛型1,泛型2,泛型3>{
}
泛型方法
泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前,
泛型标记符:
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
public class GenericMethodTest
{
// 泛型方法 printArray
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] )
{
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
}
类型通配符:
类型通配符一般是使用?代替具体的类型参数,
import java.util.*;
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
getData(name);
getData(age);
getData(number);
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
}
因为参数是List<?>所以name,age,number 都符合参数类型都可以进行传递
import java.util.*;
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
//getUperNumber(name);//1
getUperNumber(age);//2
getUperNumber(number);//3
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
public static void getUperNumber(List<? extends Number> data) {
System.out.println("data :" + data.get(0));
}
}
因为参数是List<?extendsNumber>表示参数继承于Number,都是int类型,其中name是String不符合参数类型,所以getUperNumber(name)会报错
List<?extendsNumber>表示参数只能接受Number及其下层子类类型,
类型通配符下限通过形如 List<? super Number> 来定义,表示类型只能接受 Number 及其上层父类类型
Set接口
set是Collection的子接口
set的特点:
- 无序:存取顺序不一样
- 不可重复:不可存储重复的元素
- 没有像LinkedList集合中有索引
set的实现类
:set的实现类HashSet,TreeSet
Hashset的底层原理是哈希表
TreeSet的底层原理是二叉树
HashSet
HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。HashSet 是无序的,即不会记录插入的顺序。
HashSet 不是线程安全的
保证唯一性的原理:需要重写HashCode和equals方法,
HashCode:区分地址值
equals:区分值
首先判断哈希值是否一致,如果一致则去重,如果不一致直接存储
然后判断值是否一致,如果不一致直接存储,如果不一致去重
HashSet的方法
- 通过add方法添加元素
- 通过contains来判断元素是否存在
- 通过remove来删除元素
LinkedHashSet
LinkedHashSet是HashSet的一个子类
LinkedHashSet是有序的,存取的顺序一致,也是不可重复的
Map双列集合
Map是双列集合的顶层接口
Map描述的是一个数据(key)到另一个数据(value)的映射关系
通过key来寻找value
Map集合的特点
- Key是唯一的不能重复的
- value是不唯一的,但一个key只能对应一个value
Map的所有操作都是对应键的
1.1.Map的常用方法
在Map中添加元素用的是put方法
put(K key,V Value),将键值对添加到指定集合当中
删除元素用的是remove方法
remove(K key)并返回删除的值,如果不存在则不操作
clear():清空集合
size()返回集合中键值对的个数
get(Object key)根据键值对获取值,如果不存在则返回null
containsKey(Object key)判断集合中是否含有该键
containsValue(Object value)判断集合中是否含有该值
Map集合的遍历
- 使用获取Map集合中的键,放到Set集合当中,再遍历set集合取出键,根据键获取value
- 获取Map集合当中的所有键:Set keySet()方法
- 遍历set集合,使用for循环或者for-each循环,或迭代器遍历
- 获取每个键后,根据键获取对应的值 V get(K key)
特点:获取键之后,还需要通过集合来获取值
- 获取Map集合的键值对对象(Entry),存储到Set集合当中,遍历Set集合,获取到每一个键值对对象(Entry),根据键值对对象,来获取键和值
- 根据Map集合来获取键值对对象,并放在Set集合当中
Set<Map.Entry<K,V> >entrySet()
- 遍历set集合,获取每个键值对对象,,使用迭代器遍历,或者for-each遍历或者增强for循环
- 得到键值对对象后,根据键值对对象再获取键和值
获取key:getKey();
获取value:getValue();
HashMap
HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
HashMap 是无序的,即不会记录插入的顺序。
HashMap的初始容量是16
HashMap是线程不安全的
HashMap自动扩容时会扩大为原来的2倍,默认扩容因子为0.75,即达到最大容量的75%时开始扩容
Hashtable
Hashtable底层也是哈希表数据结构,是线程安全的,其中方法都带有synchronized关键字,效率较低
Hashtable的key值和value值不能为null,HashMap的key和value都可以为null
Hashtable的初始化容量是11,默认加载因子是0.75
Hashtable的扩容是原容量*2+1
LinkedHashMap
是Map接口的实现类,是HashMap的子类
和HashMap的不同之处是:可以记录元素存取的顺序,存取顺序一致
LinkedHashMap的底层是:哈希表+双向链表
LinkedHashMap也是线程不安全的
Collections工具类
该类中提供了多种操作集合的方法
将所有元素添加到指定集合当中
<T> static boolean addAll(Collection<? super T>c,T...elements
查找元素在指定集合中存在了几次
static int frequency(Collection c,Object o)
打乱集合元素的位置
static void shuffle(List<?> list)
不可变集合
不可变的List集合
List<String> list = List.of(E...element);
不可变的Set集合
Set集合中的值不能重复
Set<String> set = Set.of(E...element);
在不可变集合当中不能进行修改,删除,添加操作
不可变的Map集合
Map集合中的键不能重复
最多存储20个,10个键值对
Map<String,String> map = Map.of(K k1,Vv1);
存储超过10个键值对时,需要传入键值对对象
Map<Object,Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]))
Map.copyof(hashMap)