Java 集合(底层解析)
- 使用数组存储对象具有一些弊端,而Java集合就像一种容器,可以动态的把多个对象的引用放入容器中
- 数组在内存中存储的特点:
- 数组初始化以后,长度就确定了
- 数组声明的类型,就决定了进行元素初始化的类型
- 数组在存储数据方面的弊端:
- 数组初始化以后,长度就不可变了,不便于扩展
- 数组中提供的属性和方法少,不便于进行添加,删除,插入等操作,且效率不高,同时无法直接获取存储元素的个数
- 数组存储的数据是有序的,可以重复的。 存储数据的特点单一
- Java集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组
1、Collection 接口
单列数据,定义了存取一组对象的方法的集合
iterator() :返回 Iterator 接口的实例,用于遍历集合元素
- Iterator 对象称为迭代器(设计模式的一种),主要用于遍历Collection 集合中的元素
- 迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的细节。迭代器模式,就是为容器而生。
- Collection接口继承了Iterable接口,该接口有一个iterator() 方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用于返回一个实现了Iterator接口的对象
- Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认指针都在集合的第一个元素之前。
1.1 List
元素有序、可重复的集合。
-
ArrayList:作为List的主要实现类,线程不安全的,效率高,底层使用数组存储
ArrayList list = new ArrayList();
list.add(123)...;
ArrayList list = new ArrayList();
list.add(123);
-
LinkedList:底层使用双向链表存储,对于频繁的插入、删除操作,比ArrayList效率高
LinkedList list = new LinkedList();
list.add(123);
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;
}
}
-
Vector:线程安全的,效率低,底层使用数组存储
1.2 Set
元素无序、不可重复的集合。
以HahSet为例:
- 无序性:不等于随机性。存储的数据在底层数组(初始长度16,当使用率超过0.75,则扩容为原来的2倍)中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的
- 不可重复性:保证添加的元素按照equals() 判断时,不能返回true。即:相同的元素只能添加一个
- 向Set中添加的数据,其所在的类一定要重写hashCode()和equals()方法:相等的对象必须有相等的散列码(哈希值)
添加元素的过程:以HashSet为例
首先通过散列算法确定元素需添加在数组中的具体位置,如果该位置上有元素了,则比较哈希值,如果哈希值不一样,则该元素以链表的形式添加在该位置,如果哈希值一样,则通过equals()方法比较,如果还是一样则不会添加到集合
-
HashSet:Set接口的主要实现类,线程不安全,可以存储null值 -
LinkedHashSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历 将数据封装到了Node节点中,对于频繁的遍历操作,LinkedHashSet效率高于HashSet -
TreeSet:可以按照添加对象的指定属性,进行排序。
-
向TreeSet中添加的数据,要求是相同类的对象 -
两种排序:自然排序和定制排序 class User{
String name;
int age;
}
@Override
public int compareTo(Object o){
if(o instanceof User){
User user = (User)o;
int compare = -this.name.compareTo(user.name);
if(compare != 0){
return compare;
}else{
return Integer.compare(this.age,user.age);
}
}else{
throw new RuntimeException("输入的类型不匹配")
}
}
public void test(){
Comparator<User> com = (o1,o2) -> {
if (o1 != null && o2 != null){
return Integer.compare(o1.getAge(), o2.getAge());
} else {
throw new RuntimeException("传参不能为空");
}
};
Set set = new TreeSet(com);
}
2、Map 接口
双列数据,保存具有映射关系“key-value”的集合
Map 中的key:无序的、不可重复的,使用Set存储所有的key ;key所在的类要重写equals() 和 hashCode()
Map 中的value:无序的、可重复的,使用Collection存储所有的value
一个键值对:key-value构成了一个Entry对象。
Map 中的entry:无序的、不可重复的,使用set存储所有的entry
-
HashMap:作为Map的主要实现类;线程不安全,效率高;可存储null的key-value
HashMap map = new HashMap();
map.put(key1,value1);
new HashMap();
-
LinkedHashMap:作为HashMap的子类:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素,对于频繁的遍历操作,执行效率高于HashMap
static class Entry<K,V> extends HashMap.Node<K,V>{
Entry<K,V> before,after;
Entry(int hash,K key,V value,Node<K,V> next){
super(hash,key,value,next);
}
}
-
TreeMap:可按照key对集合进行排序,实现排序遍历。底层使用红黑树
-
HashTable:作为Map的古老实现类;线程安全,效率低;不可存储null的key-value -
Properties:作为Hashtable的子类,常用于处理配置文件,key和value都是String类型的
|