java基础
待补
文章目录
前言
本篇聊一下java基础中的一大重要内容——集合。
1.集合类概述
1.1常用集合知识体系
以上为常用集合类继承体系,作为扩充,我们可能还需要额外了解一下HashTable和ConcurrentHashMap
1.2和数组的区别
集合和数组一样是一种容器,但也有区别:
- 数组长度固定,集合长度可变。
- 数组存放基本类型或引用类型,集合存放引用类型。
2.Collection单列集合根接口
是单列集合,是list接口和set接口的父接口,单例集合的根接口。
Collection常用方法(set和list接口共用):
add(E e):把元素填入集合
remove(Object o):把元素从集合中移除
isEmpty():判空,返回boolean值
iterator():迭代器,放回集合中每个对象,用于遍历
size():集合中元素个数,返回int值
下面演示用迭代器遍历集合元素:
import java.util.*
public class Muster{
public static void main(String args[]){
//创建集合对象
Collection list=new ArrayList<>();
//填入三条数据
list.add("测试数据1");
list.add("测试数据1");
list.add("测试数据1");
//调用iterator()方法获取迭代器对象
Iterator it =list.iterator();
//使用hasNext()方法判断集合是否结束
while(it.hasNext()){
//把下一个元素赋值给变量str
String str =(String)it.next();
//打印当前元素
sout(str);
}
}
}
3.List集合
3.1介绍
Collection的一个子接口,
- 集合中元素允许重复,元素顺序就是对象插入顺序
- 可以使用索引来访问。
- 除了Collection接口的方法外还额外定义了两个方法:
get(int index):获取指定索引位置的元素
set(int index,object o):修改指定位置的元素为指定对象
3.2ArrayList
实现了可变的数组,可以保存所有种类元素,包括null。
根据索引访问元素,查询快插入慢,如下是常用方法。
常用方法
添加元素
boolean add(E e):将指定的元素添加到此列表的末尾(可选操作)。
void add(int index, E element):将指定的元素插入此列表中的指定位置(可选操作)。
boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到此列表的末尾,顺序由指定集合的迭代器确定(可选操作)。
boolean addAll(int index, Collection<? extends E> c):将指定集合中的所有元素都插入到列表中的指定位置(可选操作)。
删除元素
E remove(int index):移除此列表中指定位置上的元素(可选操作)。
boolean remove(Object o):从列表中移除指定元素的第一个匹配项(如果存在)(可选操作)。
boolean removeAll(Collection<?> c)**:移除列表中那些也包含在指定集合中的所有元素(可选操作)。 **boolean retainAll(Collection<?> c):仅保留此列表中那些也包含在指定集合中的元素(可选操作)。
void clear():移除此列表中的所有元素(可选操作)。
访问元素
E get(int index):返回列表中指定位置的元素。
int indexOf(Object o):返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
int lastIndexOf(Object o):返回此列表中最后出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。
3.4LinkedList
使用链表保存元素,查询慢插入快。
底层使用双链表存储数据,LinkedList 只有 3 个属性,分别为: 头节点 first 、 尾节点 last 以及代表数量的 size。
其中Node是内部类,内部记录数据、前一节点、后一节点
4Set集合
- 没有特定排序规则,
- 元素不可重复
实现类有:
HashSet:
由hash表支持,不保证迭代顺序
TreeSet:
可以保证遍历时候的顺序(使用迭代器取出的元素会按某种规则排布)
4.1Hashset
底层是哈希表,哈希表底层是一个数组,通过哈希值计算出存储的索引位置。
哈希值通过Object对象中的hashcode方法来计算。
哈希表:jdk1.8前是数组+链表,jdk1.8后是数组+链表+红黑树
hashcode方法:默认使用地址值计算,因此各个对象的哈希值不同。但可以重写hashcode方法,让其用属性值进行计算,这样一来即使是不同对象,只要属性值相同,也会拥有相同的哈希值。
hashSet元素添加底层原理
转换红黑树的时机
明白hashSet中存储的原理后,需要注意:
三大特点解析
为什么无序?
哈希表底层是一个数组,遍历哈希表就是从头遍历这个底层数组,但存放的数据在这个数组中并不是按顺序存放,所以遍历底层数组时也不会是存入时的顺序。
(比如我第一个存入的数据计算了哈希值后存储在数组的2号位,但第二个存入的数据计算哈希值后却存储在数组的1号位,于是获取的顺序就会反过来)
为什么无索引?
因为底层的链表和红黑树本身就不是连续存储的,无法通过索引快速获取元素,使用hash的方式已经能够快速获取数据了。所以也就没必要引入索引这个概念了。
为什么数据不重复?
上面提到底层存储时会使用hashcode判断存储位置,然后使用equals()方法比较元素,元素内容相同就不进行存储。
补充:其实本身HashSet底层就是用一个HashMap存数据,只是将value对使用者隐藏了而已。
4.2LinkedHashSet
相较HashSet,额外用双链表来链接所有元素。
于是相较HashSet,可以保证存取顺序一致
4.3TreeSet
底层使用红黑树实现,可以对元素进行排序。
如果是存储自定义的类对象,还需要在自定义类中提供比较规则。
有两种方式来决定TreeSet的比较规则:重写compareTo、比较器
4.3.1自定义比较规则
需要自定义类实现Comparable接口并重写其中的compareTo方法,在该方法中设置比较规则。
如:我们用学生类的年龄为标准进行排序:
这个方法是TreeSet在进行元素添加时使用的参考函数,用来确定新元素应该添加到树的哪一个位置。
新元素会从根开始与已有元素依次比较,返回值为负数就把新元素放左子树上,返回值为正数就把新元素放右子树上。如果要添加的位置已有元素,就继续比较。最终形成查找树,再通过红黑树规则转换为真正的红黑树。
4.3.2比较器指定规则
这种方式可以在创建集合对象时传入一个比较器对象来指定规则。
规则的具体用法与上一种方式一样。
5Map集合
存储key-value映射,一个key只指定一个value,但一个value可以被多个key指定
5.1Map接口
Map接口额外提供的方法:
put(K key,V value):集合中添加映射
containsKey(Object key):查看有没有指定名称的key的元素
containsValue(Object value):查看有没有指定名称的value元素
get(Object key):获取传入的key对应的value值
keySet():返回一个由所有的key组成的Set集合
values():返回集合中所有value组成的Collection集合
5.2HashMap
底层也是哈希表,因此存储的规则等与前面说的hashSet一致,只不过存储的元素是Entry<K,V>对象。
使用hashcode和equals方法保证元素不重复
不保证元素顺序,可以使用null键和null值
添加元素时的判断逻辑如下:
也就是说,HashMap并不在意一个Node中的Value是什么,仅仅使用key(使用hashcode和equals方法)来判断整个Node结点是否能够添加进去。
5.3LinkedHashMap
继承自HashMap,额外有双链表链接存储的Entry<K,V>元素。
5.4TreeMap
可以保证元素按顺序输出,但键和值不可以为空值
与TreeSet一样底层是红黑树。
补充:即HashMap与HashSet一样,TreeMap与TreeSet一样。区别无非是list系列的集合存储普通的引用数据,Map系列集合存储Entry<K,V>类型对象。
5.5HashTable
底层方法被sychonized修饰,可保证并发安全。
5.6ConcurrentHashMap
使用分段锁保证并发安全
总结
本篇中简要介绍一下java中的集合。