Java集合

集合:存储操作多个对象的作用。

数组 VS 集合
1.数组、集合都是对多个数据进行存储、操作的。
2.数组存储特点
一旦初始化后,其长度、元素类型就确定了。
数组存储数据有序、可重复。
3.数组存储弊端
不方便扩容、现有方法较少、增删改操作不方便,效率也不高。
对于无序、不可重复的存储需求无法满足。
4.集合存储的优点
解决数组存储存在的弊端。丰富的方法,便于开发操作。

Java集合可分为 Collection 和 Map 两种体系。
|—Collection接口: 单列数据,定义了存取一组对象的方法的集合
|—List接口: 元素有序、可重复的集合。(动态数组)
|—Vector类
|—ArrayList类
|—LinkedList类
|—Set接口: 元素无序、不可重复的集合
|—HashSet类
|—LinkedHashSet类
|—TreeSet类
|—Map接口: 双列数据,保存具有映射关系"key-value"对的集合
|—Hashtable类
|—Properties类
|—HashMap类
|—LinkedHashMap类
|—TreeMap类
--------------------------------------- Collection体系 ---------------------------------------
Collection接口
List接口(有序、可重复、可扩容)
ArrayList实现类
LinkedList实现类
Vector实现类
Set接口(无序、不可重复、可扩容)
HashSet实现类
LinkedHashSet实现类
TreeSet实现类
详细展开
List接口的实现类
ArrayList实现类
ArrayList为JDK1.2新增,它是List接口的主要实现类,无特殊情况下使用该类即可满足列表操作需求。
底层存储原理:
底层采用Object类型的一维数组存储:Object[] elementData;
JDK1.8之前,无参构造器初始化时, 构造器中 elementData = new Object[10];
JDK1.8,无参构造器初始化时,构造器中不new对象 elementData = {},调用add方法添加元素时判断
如果elementData = {}则new对象,数组长度根据当前添加的元素个数判断,个数<=10则长度设置为10
个数>10则以实际添加的元素个数为数组长度。
针对扩容,如果(添加的元素个数+已存储的元素个数)>原数组长度,则判断(添加的元素个数+已存储的元素个数)>1.5原数组长度
若是则以(添加的元素个数+已存储的元素个数)为新的数组长度,否则以1.5
原数组长度作为新数组长度
提示:扩容过程影响效率,建议在创建ArrayList对象时显示的指定足够的容量,即 ArrayList list = new ArrayList(长度);
ArrayList类中的方法没有都是非同步方法,线程不安全的,效率高。
LinkedList实现类
LinkedList为JDK1.2新增,它采用的是双向链表存储结构,适合频繁的插入、删除操作。
底层存储原理:
类中封装了一个静态内部类Node、属性Node first、Node last。
静态内部类有3个属性:元素、Node next(指向下一个Node)、Node prev(指向上一个Node)
每个元素都封装成内部类的对象,对象中的属性next、prev分别指向下一个、上一个对象,从而形成双向链表结构
LinkedList类中的方法没有都是非同步方法,线程不安全的,效率高。
Vector实现类
Vector类在JDK1.0版本就存在,底层存储原理跟ArrayList是一致的,但是Vector类中的方法全部为同步方法,线程安全但效率低。
此类目前不常用了,有ArrayList类所替代。

面试题:ArrayList、LinkedList、Vector三者的异同?
	相同点:
		都实现了List接口,存储数据特点都是: 有序、可重复、可扩容。
	不同点:
		ArrayList为List接口的主要实现类,未处理线程安全问题、效率高,底层存储采用Object[]
		Vector为List接口的古老实现类,是线程安全的、效率低,底层存储采用Object[]
		LinkedList对于频繁插入、删除操作此类型比ArrayList效率高。底层采用双向链表

Set接口的实现类
HashSet实现类
HashSet类作为Set接口的主要实现类,可以存储null。
底层存储原理:底层采用HashMap存储。
LinkedHashSet实现类
LinkedHashSet类为HashSet类的子类,遍历时可以按照添加的顺序遍历。
TreeSet实现类
底层采用红黑树存储,要求存入的数据是同一个类的。new该类的对象时,使用不同的构造器会采用不同的方法排序。
无参构造器:TreeSet treeSet = new TreeSet(); 此构造器new的对象,添加的元素将按照元素所属类中的compareTo方法排序(自然排序)
有参构造器:TreeSet treeSet = new TreeSet(Comparator对象); 此构造器new的对象,添加的元素将按照Comparator对象所属类中的compare方法排序(定制排序)
HashSet可以理解为只有key的HashMap,value是一个默认静态常量(new Object())。

常用方法
Collection接口中的常用方法
boolean add(Object obj) 添加元素,返回值为添加状态(true-成功|false-失败)
boolean addAll(Collection coll) 添加集合,将指定集合中的元素添加到集合,返回值为添加状态(true-成功|false-失败)
int size() 获取实际元素个数
boolean isEmpty() 判断集合中是否有实际的元素(size是否为0),返回值(true-有|false-无)
boolean clear() 清空集合中的元素
boolean contains(Object obj) 判断集合中是否存在某个对象,返回值(true-存在|false-不存在)。采用对象所属类中equals方法判断
boolean containsAll(Collection coll) 判断指定集合中的元素是否全部在集合中,返回值(true-存在|false-不存在)。采用对象所属类中equals方法判断
boolean remove(Object obj) 移除某个元素,返回值(true-成功|false-失败)。采用对象所属类中equals方法判断元素是否存在
boolean removeAll(Collection coll) 移除指定的多个元素(差集),返回值(true-成功|false-失败)。采用对象所属类中equals方法判断元素是否存在
boolean retainAll(Collection coll) 交集,返回值(true-成功|false-失败)。采用对象所属类中equals方法判断元素是否存在
boolean equals(Object obj) 判断两个集合顺序、内容是否一样,返回值(true-是|false-否)。采用对象所属类中equals方法判断元素是否相同
int hashCode() 返回当前对象的哈希值
Object[] toArray() 集合 -> 数组
扩展:数组 -> 集合 ArrayList arrList = Arrays.asList(数组); //数组类型要求用引用类型(int数据用Integer)
List接口中的常用方法
void add(int index, Object obj) 在指定位置插入一个元素
boolean addAll(int index, Collection coll) 在指定位置插入多个元素
Object get(int index) 返回指定位置的元素
int indexOf(Object obj) 返回某个对象在集合中首次出现的位置,如果不存在则返回-1
int lastIndexOf(Object obj) 返回某个对象在集合中最后1次出现的位置,如果不存在则返回-1
Object remove(int index) 移除某个位置上的元素,并返回移除的元素
Object set(int index, Object obj) 修改某个位置的元素为obj
List subList(int beginIndex, int endIndex) 截取列表,范围[beginIndex,endIndex)
总结:
增: boolean add(Object obj)
删: boolean remove(Object obj) | Object remove(int index) //如果参数是int型则按索引删除,如果参数是对象则按元素删除。
改: Object set(int index, Object obj)
查: Object get(int index)
插入: void add(int index,Object obj)
长度: int size()
遍历:
增强for循环
for(Object obj : 集合){}
迭代器
Iterator iter = 集合.iterator();
Object obj;
while(iter.hasNext()){
obj = iter.next();
}
普通for循环
for(int i=0;i<集合.size();i++){
System.out.println(集合.get(i));
}
--------------------------------------- Map体系(键值对) ---------------------------------------
Map接口
HashMap实现类
当前Map接口的主要实现类,线程不安全,效率高。可以存储null的key、value
LinkedHashMap实现类
LinkedHashMap类为HashMap类的子类,遍历时可以按照添加的顺序遍历。
原理:LinkedHashMap类多2个Node属性,指向前一个、后一个Node,对于频繁遍历的操作,此类效率高于HashMap
TreeMap实现类
底层存储采用红黑树原理,添加的元素按key进行排序。
Hashtable实现类
古老的Map接口的实现类,线程安全,效率低。不可以存储null的key、value
Properties实现类
Properties类为Hashtable类的子类,常用来处理配置文件,key和value都是String型

key:无序、不可重复(Set存储)
value:无序、可重复
key-value构成一个元素Entry,是Entry对象中属性key、属性value。
Entry:无序、不可重复(Set存储)

重点:HashMap底层实现原理:JDK1.7
HashMap map = new HashMap();
实例化后,底层创建了长度为16的一维数组 Entry[] table = new Entry[16];
添加元素: map.put(key1, value1); //key1-value1封装进Entry, 记作Entry1
首先调用key1所在类的hashCode方法计算key1的哈希值,此哈希值经过某种算法计算其在一维数组存放的索引[0-length-1],
(存放的索引位置与 key 的哈希值、数组的长度有关,底层算法计算存储索引位置是根据这两个值计算的。)
如果此位置为null,此时 Entry1 直接可添加成功!①
如果此位置不为null(此位置可能存在1个或n个Entry,多个Entry采用单链表结构链接),key1与此位置上的所有key逐一
比较哈希值:
如果key1哈希值与此位置上已有key的哈希值都不相同,则 Entry1 可添加成功!②
如果key1哈希值与此位置上某一个key2的哈希值相同,则key1调用equals(key2)方法比较两者内容是否相同(key要求是同一类型)
如果内容不相同,则 Entry1 可添加成功!③
如果内容相同,则 key1 的值value1替换key2的值value2。
在不断添加过程中,会涉及扩容的问题,默认的扩容方式为:扩容为原容量的2倍,并将原有数据复制过来。
扩容条件:元素个数>=临界值(原容量*加载因子) 且 要存储的数组位置不为null (默认容量16,默认加载因子0.75f)

JDK1.8相较于JDK1.7在底层实现方面的不同:
	1.new HashMap();在底层没有创建长度为16的数组,而是在首次调用put方法添加的时候创建。Node[] table = new Node[16];
	2.JDK1.7中底层实现是将key-value封装进 Entry 对象,JDK1.8底层实现是将 key-value封装进 Node 对象。(只是名字不同)
	3.JDK1.7底层实现中链表添加方式:新添加的元素放在数组位置,并指向原来该位置的元素(7上)
	  JDK1.8底层实现中链表添加方式:新添加的元素挂在数组位置的最后一个元素的next指针上(8下)
	4.JDK1.7底层结构只有:数组+链表;JDK1.8底层结构:数组+链表+红黑树
		当数组的某一个索引位置上的元素个数>=8 且 当前数组长度>=64
		此时该索引位置上的元素之间改为用红黑树结构存储(提升查询效率)
	HashMap中的常见属性
		DEFAULT_INITIAL_CAPACITY 默认数组长度:16
		DEFAULT_LOAD_FACTOR      默认加载因子:0.75
		TREEIFY_THRESHOLD        链表长度临界值:8
		MIN_TREEIFY_CAPACITY     哈希表长度(数组长度)临界值:64
		扩容临界值 = (数组长度*加载因子)
		说明:
			扩容条件:①元素个数>=扩容临界值 且 要存储的数组位置不为null 
			          ②链表元素个数>=8 且 数组长度<64 (JDK1.8)
					  加载因子越大,数组扩容次数越少,链表越长。
			链表结构转为红黑树结构条件:
				链表元素个数>=8 且 数组长度>=64 (JDK1.8)

说明:
向HashMap(HashSet)集合中添加数据,其元素所在的类一定要重写equals、hashCode方法
重写的hashCode()和equals()尽可能保持一致性(相等的对象必须具有相等的哈希值)

常用方法
增、删、改操作
Object put(key,value) 添加(或修改)一个键值对
void putAll(Map m) 添加多个键值对
Object remove(Object key) 移除一个键值对,按照key查找要移除的键值对。返回移除的key对应的value
void clear() 清空当前map中的所有数据
查询操作
Object get(Object key) 获取指定key对应的value
boolean containsKey(Object key) 判断是否包含指定的key
boolean containsVaule(Object value) 判断是否包含指定的value
int size() 返回map中key-value对的个数
boolean isEmpty() 判断当前map是否为空{}
boolean equals(Object obj) 判断当前map和参数obj是否相等
元视图操作
Set keySet() 返回所有key构成的Set集合
Collection values() 返回所有value构成的Collection集合
Set entrySet() 返回所有key-value构成的Set集合
Map无法转成迭代器,遍历方法:keySet()方法获得所有key,转成迭代器遍历所有key
调用get(Object key)方法获取key对应的value值。
--------------------------------------- 迭代器 ---------------------------------------
Iterator iterator() 返回集合对应的迭代器,用于遍历集合元素。每调用一次就会返回一个迭代器,默认游标在第一个元素之前。
Iterator对象取下一个元素:对象.next()
Iterator对象判断下一个元素是否存在(true-存在|false-不存在):对象.hasNext()
Iterator对象调用remove()方法删除某个元素:对象.remove()
遍历:
Iterator iter = 集合对象.iterator();
while(iter.hasNext()){
Object obj = iter.next();
}
iter = 集合对象.iterator();//再次遍历前 iter 要重新赋值,不然iter.hasNext()不满足条件
while(iter.hasNext()){
Object obj = iter.next();
}
删除某个对象:
Iterator iter = 集合对象.iterator();
while(iter.hasNext()){
Object obj = iter.next();
if(“Tom”.equals(obj)){
iter.remove();//删除, 注意:调用remove后,必须next()后才能再次调用remove。
}
}
JDK5.0新特性:增强for循环,遍历集合
for(Object obj : 集合/数组){
System.out.println(obj); //依次从集合中取出元素拷贝给 obj ,此时修改obj不影响元素。
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值