集合
2021-06-06
Java集合框架概述
- 集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt, .jpg,.avi,数据库) - 数组在存储多个数据方面的特点:
- 一旦初始化以后,其长度就确定了。
- 数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。比如: String[] arr;
int[ ] arr; 0bject[] arr;
- 数组在存储多个数据方面的缺点:
- 一旦初始化以后,其长度就不可修改。
- 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
- 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
- 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
- 集合框架
|----Collection
|----List接口:存储有序的、可重复的数据。 -->动态的数组
|----ArrayList、LinkedList、Vector
|----Set接口:存储无序的、不可重复的数据。 -->高中学过的“集合”
|----HashSet、LikedHashSet、TreeSet
|----Map:双列集合,用来存储一对数据(key -- value)。 -->高中学的函数 y = f(x)
|----HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
Collection
- Collection接口中的方法(与生俱来的抽象方法)
//14个方法
Collection coll = new ArrayList();
//1.add(Objetct e) :将元素e添加到集合coll中
coll.add("AA");
coll.add("BB");
coll.add(123);
coll.add(new Date());
//2.size() :获取集合中的元素个数
System.out.println(coll.size());
//3.addAll(Collection coll1) :将coll1集合中的元素添加到当前集合中
Collection coll1 = new ArrayList();
coll.addAll(coll1);
//4.clear() 清空集合元素
coll.clear();
//5.isEmpty() :判断当前集合是否为空 (return size == 0;)
System.out.println(coll.size());
System.out.println(coll.isEmpty());
//6.contains(Object obj) :判断当前集合中是否包含obj
//在判断时会调用obj所在类的equals(),按顺序依次和集合中的每个元素进行比较
//所以:向Collection接口的实现类的对象中添加数据obj时,要求obj所在的类重写equals()方法
boolean contains = coll.contains(new Person(Jerry,20));
//7.containsAll(Collection coll1) :判断coll1中的元素是否都存在于本集合中
//8.bollean remove(Object obj) :移除本集合中的obj元素,并返回是否移除成功
//9.bollean removeAll(Collection coll1) :移除本集合中的包含在coll1中的所有元素(移除交集),并返回是否移除成功
//10.retainAll(Collection coll1) 求交集
//11.equals(Object obj) :obj是集合 比较两个集合是否相同,ArraysList是有序的,顺序不一致则为false
//12.hashCode() :返回哈希值
//13.集合-->数组 toArray()
Object[] arr = coll.toArray();
//数组-->集合?
List<String> list = Arrays.asList(new String[]{"AA","BB","CC"});
List list1 = Arrays.asList(new int[]{123,456});
List list2 = Arrays.asList(new Integer[]{123,456});
//14.iterator() :返回Iterator接口的实例,用于遍历集合元素,后面再讲
Iterator 迭代器接口
- Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象
- Iterator称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素
- GOF给迭代器模式的定义为:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。迭代器模式就是为容器而生。
- Iterator仅用于遍历集合,Iterator本身并不提供承装对象的能力,如果需要创建Iterator对象则必须有一个被迭代的集合
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
hasNext();
next();
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
Iterator iterator = coll.iterator();
while(iterator.hasNext()){//hasNext判断是否还有下一个元素
System.out.println(iterator.next());//next() ①指针下移 ②将下移以后集合位置上的元素返回
}
remove();//可以在遍历的时候删除集合中的元素,不同于集合直接调用remove()
//注意:!如果还未调用next()或在上一次调用next方法之后已经调用了remove方法再调用remove都会报IllegalStateException
Iterator iterator = coll.iterator();
while(iterator.hasNext()){//hasNext判断是否还有下一个元素
Object obj = iterator.next();
if("TOM".equals(obj)){
iterator.remove();
}
}
iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
- foreach
- JDK5.0提供了另一种遍历集合的方式:foreach循环迭代访问Collection和数组
- 这种遍历方式不需要获取Collection或数组的长度,无需使用索引访问元素
- 遍历集合的底层其实也是使用Iterater迭代器
//for(集合元素的类型 局部变量 : 集合对象)
for(Object obj : coll){
System.out.println(obj);
}
//for(数组元素的类型 局部变量 : 数组对象)
int[] arr = new int[]{1,2,3};
for(int i : arr){
System.out.println(i);
}
练习题:
@Test
public void test(){
String arr = new String[]{"MM","MM","MM"};
方式一:
for(int i = 0; i < arr.length; i ++){
arr[i] = "GG";
}
方式二:
for(Sting s : arr){
s = "GG";
}
for(int i = 0; i < arr.length; i ++){
System.out.println(arr[i]);
}
//方式一打印GG,方式二打印MM
}
Collection子接口之一—List
- 鉴于JAVA中用数组来存储数据的局限性,我们通常用List替代数组
- List集合中元素有序且可重复,集合中的每个元素都有其对应的顺序索引
- List容器中的元素都对应一个int型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
|----ArrayList:List接口的主要实现类 jdk1.2 线程不安全 效率高,底层使用Object[] elementData存储
|----LinkedList: jdk1.2 底层使用双向链表存储,对于频繁的插入和删除操作,使用此类效率比ArrayList高
|----Vector :List接口的古老实现类 jdk1.0 线程安全 效率低,底层使用Object[] elementData存储
- ArrayList底层源码分析
//jdk7
ArrayLisy list = new ArrayList();//底层创建了长度是10的Object[] elementData数组
list.add(123);//elementData[0] = new Integer(123);
...
list.add(321);//如果此次添加导致底层elementaData数组容量不够,则扩容。
//默认情况下扩容为原来的1.5倍,然后将原来数组中的数据复制到新的数组中
//结论:建议开发中使用带参的构造器
ArrayList list = new ArrayList(int capacity);
//jdk8作了一些变化
ArrayList list = new ArrayList();//底层Object[] elementData初始化为{},并没有创建长度是10的数组
list.add(123);//第一次调用add时,底层才创建了长度为10的数组,并将123添加到elementData
//后面的添加和扩容操作与jdk7一样
//总结:jdk7中ArrayList的创建类似于单例的饿汉式 jdk8中类似于单例的懒汉式
//jdk8这种方式延迟了数组的创建,节省内存
- LinkedList底层源码分析
LinkedList list = New LinkedList();//内部声明了Node类型的first和last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象
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底层源码分析
- jdk7和jdk8中通过Vector()构造器创建对象时,底层都是创建了长度为10的数组,在扩容时,默认扩容为原来数组长度的2倍。
- 虽然它是线程安全的,但是在多线程问题中也基本不用它了,Collections工具类中有方法可以让ArrayList变成线程安全的~!
List接口中常用方法
- List除了从Collection集合继承的方法外,List集合里添加了一些根据索引来操作集合元素的方法
@Test
public void test(){
ArrayList list = new ArrayList();
lsit.add(123);
lsit.add(456);
lsit.add("AA");
lsit.add(new Person(Tom,24));
lsit.add(456);
/*1. void add(int index, Object ele):在index位置插入ele元素*/
list.add(2,"BB");
/*2. boolean add(int index, Collection eles):在index位置插入集合Collection*/
List list1 = Arrays.asList(1,2,3);
list.addAll(2,list1);
System.out.println(list.size());//9
/*3. Object get(int index); 获取指定索引位置的元素*/
System.out.println(get(0));
/*4. int indexOf(Object obj); 返回obj在集合中首次出现的位置 */
System.out.println(list.indexOf("AA"));//2
System.out.println(list.indexOf("CC"));//-1 没有就返回-1
/*5. int lastIndexOf(Object obj); 返回obj在集合中最后一次出现的位置 */
System.out.println(list.indexOf(456));//4
System.out.println(list.indexOf(789));//-1 没有就返回-1
/*6.Object remove(int index); 删除指定索引处的元素,并返回该元素*/
System.out.println(list.remove(0));//123
/*7. Object set(int index,Object ele); 设置指定索引处的元素为ele */
System.out.println(list.set(1,"CC")); //[456,"CC","TOM,24",456]
/*8. List subList(int fromIndex , int toIndex); 返回从fromIndex到toIndex位置的左闭右开区间的子集合*/
List subList = list.subList(2,4);
System.out.println(subList);//["AA","Tom,24"]
}
- 总共15+8=23个方法!总结一下常用方法
增:add(Object obj)
删:Object remove(int index) / boolean remove(Object obj)
改:set(int index,Object ele)
查:get(int index)
插:add(int index, Objecrt ele)
长度:size()
遍历:①Iterator ②增强for ③普通的循环也可以
- List的遍历
@Test//遍历
public void test(){
ArrayList list = new ArrayList();
lsit.add(123);
lsit.add(456);
lsit.add("AA");
//方式一:迭代器
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//方式二:增强for
for(Object obj : list){
System.out.println(obj);
}
//方式三:普通for
for(int i = 0 ; i < list.size() ; i ++){
System.out.println(list.get(i));
}
}
Collection接口的子接口之二----Set接口
- Set是Collection接口的子接口,它没有提供额外的方法
- Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败
- Set判断两个对象是否相同不是用 == 而是用 equals()
|----Collection
|----Set接口:存储无序的、不可重复的数据。 -->高中学过的“集合”
|----HashSet:
- HashSet是Set接口的典型实现,大多数时候使用Set集合时都是使用这个实现类
- HashSet按Hash算法来存储集合中的元素,因此具有很好的存取、查找、删除性能
- HashSet具有以下特点:
- 不能保证元素的排列顺序
- HashSet不是线程安全的
- 集合元素可以是null
- HashSet集合判断两个元素是否相等的标准:
两个对象通过hashCode()方法比较相等并且两个对象的equals()返回值也相等
|----LikedHashSet:
- LinkedHashSet它其实是HashSet的一个子类
- 底层存储结构和HashSet一致
- 添加元素的时候,还按添加顺序形成一个双向链表
- 遍历的时候,可以按照添加的顺序遍历
- 对于频繁的遍历操作,LinkedHashSet效率更高一些
|----TreeSet:
- 底层结构是二叉树(红黑树)
- 向treeSet中添加的元素,必须是相同类的对象
- 可以按照添加对象的指定属性进行排序(Comparable、Comparator)
- Set的无序性和不可重复性怎么理解?
以HashSet的无序性和不可重复性
1. 无序性 ≠ 随机性,添加元素不是按顺序存进底层数组中的,所以遍历的出来的顺序不是添加时的顺序。
元素在数组中的存储位置是哈希值决定的,由Hashcode()方法计算出哈希值
2.不可重复性:保证添加的元素按照equals()判断时,不能返回true,即相同的元素只能添加一个
HashSet添加元素的过程:
向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,根据此哈希值,通过
某种算法计算出元素a在HashSet底层数组中的存放位置(索引位置),判断此位置上是否有元素,如果没有元素则
将a放在此位置,如果此位置上有其他元素b,则比较a与b的哈希值,如果哈希值不相同,则a添加成功(注);
如果哈希值相同,则通过a.equals(b)来进行比较,如果equals方法返回true,则添加失败,如果equals方法
返回false,则a添加成功(注)。
注:元素a与b以链表的方式存储
jdk7:元素a放到数组中,指向原来的元素
jdk8:原来的元素放在数组中,指向元素a
七上八下
- hashCode()和equals()的重写
对于存储在Set容器中的对象,一定要重写equals()和hashCode(Object obj)要求相等的对象必须有相等的散列码
- TreeSet的使用
@Test
public void test(){
TreeSet set = new TreeSet;
set.add(123);
set.add("AA");//报错了,必须添加相同类的对象
}
@Test
public void test(){
TreeSet set = new TreeSet();
set.add(34);
set.add(-34);
set.add(43);
set.add(11);
set.add(8);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());//按从小到大排的
}
}
@Test
public void test(){
TreeSet set = new TreeSet();
set.add(new User(Tom,12));
set.add(new User(Jerry,12)); //报错了!User类没有实现comparable接口(没有compareTo方法)
set.add(new User(Mike,12));
set.add(new User(Jone,12));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//User类继承comparable接口,重写compareTo()方法
@Override
public int compareTo(Object o){
if(o instanceof User){
User user = (User)o;
return this.name.compareTo(user.name);
}else{
throw new RuntimeException)("输入的类型不匹配");
}
}
@Test
public void test(){
TreeSet set = nee TreeSet();
set.add(new User(Tom,12));
set.add(new User(Jerry,12));
set.add(new User(Mike,12));
set.add(new User(Jone,12));
set.add(new User(Tom,56)); //这个Tom没遍历出来,TreeSet里如果compareTo返回值是0,那就认为是相同的元素
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//稍作修改
@Override
public int compareTo(Object o){
if(o instanceof User){
User user = (User)o;
//return this.name.compareTo(user.name);
int comepare = this.name.compareTo(user.name);
if(compare != 0){
return compare;
}else{
return Interger.compare(this.age,user.age);
}
}else{
throw new RuntimeException)("输入的类型不匹配");
}
}
- 上面是自然排序
- 下面用comparator
@Test
public void test(){
Comparator com = new Comparator(){
//按照年龄从小到大排序
@Override
public int compare(Object o1,Object o2){
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else{
throw new RuntimeException("输入的数据类型不匹配");
}
}
};
TreeSet set = new TreeSet(com); //不带参数的构造器默认用自然排序
set.add(new User(Tom,12));
set.add(new User(Jerry,12));
set.add(new User(Mike,12));
set.add(new User(Jone,12));
set.add(new User(Tom,56));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
自然排序中,比较两个对象是否相同的标准为: compareTo()返回0.不再是equals().
定制排序中,比较两个对象是否相同的标准为: compare()返回0.不再是equals().
- 练习题:
练习一:
//在List内去除重复数字值,要求尽量简单
public List duplicateList(List list){
HashSet set = new HashSet();
set.addAll(list);
return new ArrayList(set);
}
练习二:
@Test
public void test(){
HashSet set = new HashSet();
Person p1 = new Person(1001,"AA");
Person p2 = new Person(1002,"BB");
set.add(p1);
set.add(p2);
System.out.println(set); /*{(1001,"AA"),(1002,"BB")}*/
p1.name = "CC";
set.remove(p1);
System.out.println(set);/*{(1001,"CC"),(1002,"BB")}*/
set.add(new Person(1001,"CC"));
System.out.println(set);/*{(1001,"CC"),(1002,"BB"),(1001,"CC")}*/
set.add(new Person(1001,"AA"));/*{(1001,"CC"),(1001,"AA"),(1002,"BB"),(1001,"CC")}*/
System.out.println(set);
}
Map
|----Map:(JDK1.2)双列数据,存储key-value键值对----类似于高中学的函数y=f(x)
|----HashMap:作为Map的主要实现类(JDK1.2),线程不安全的,效率高;可以存储null的key和value
|----LinkedHashMap:(JDK1.4)在HashMap基础上加了一对指针,保证在遍历Map元素时,可以按照添加元素顺序进行遍历;对于频繁的遍历操作,它的效率比HashMap更高
|----TreeMap:(JDK1.2)可以按照添加的key-value进行排序,实现排序遍历(key的自然排序或者定制排序);底层使用红黑树
|----Hashtable:作为Map的古老实现类(JDK1.0)类似于Vector,线程安全,效率低;不能存储null的key和value;即使是多线程的也不用它,而是使用Collections工具类将HashMap变为线程安全的
|----Properties:常用来处理配置文件;key和value都是String类型
public class MapTest{
@Test
public void test(){
Map map = new HashMap();
map.put(null,null);//ok
map = new Hashtable();
map.put(null,null);//Exception
}
}
HashMap的底层结构:JDK7之前:数组+链表
JDK8:数组+链表+红黑树
面试题:1.HashMap的底层实现原理
2.HashMap和Hashtable的异同
3.CurrentHashMap和Hashtable的异同(暂时不讲)
- Map结构的理解
Map中的key:无序的、不可重复的,使用Set存储所有的key ---->key所在的类要重写hashcode()和equals()(HashMap为例;TreeMap不同)
Map中的value:无序的,可重复的,使用Collection存储所有的value ---->value所在的类要重写equals()
一个键值对 key--value 构成了一个Entry对象。Map中的entry是无序的不可重复的,使用Set存储所有的entry
- HashMap的底层实现原理
JDK7
HashMap map = new HashMap();
在实例化以后,底层创建了长度是16的一维数组Entry[] table
map.put(key1,value1) (在此之前可能已经执行过多次put了)
首先调用key1所在类的hashCode()计算key1的哈希值,此哈希值经过某种算法计算之后,得到在Entry数组中存放的位置,
如果此位置上的数据为空,则key1-value1添加成功。----情况1
如果此位置上的数据不为空(意味着此位置上存在着一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
如果key1的哈希值和已经存在的多个数据的哈希值都不相同,此时key1-value1添加成功----情况2
如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较key1.equals(key2)
如果equals()返回false:此时key1-value1添加成功----情况3
如果equals()返回true:此时使用value1替换value2
补充:1.关于情况2和情况3,此时key1-value1和原来的数据以链表的方式存储
2.在不断地添加过程中会涉及到扩容问题,默认的扩容方式:扩容为原来容量的两倍,并将原有的数据复制过来
-------------------------------------------------------------------------------------------------------------------
JDK8相较于JDK7在底层实现方面的不同:
1.HashMap map = new HashMap();在实例化以后,底层没有创建长度是16的数组
2.JDK8底层数组不是Entry[] 而是Node[]
3.首次调用put()方法时,底层创建长度为16的数组
4.JDK7底层结构为 数组+链表,JDK8底层结构为 数组+链表+红黑树
当数组某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组长度>64时
此索引位置上的所有数据改为使用红黑树存储。
- HashMap底层源码分析
面试题:
谈谈你对HashMap中put/get方法的认识,如果了解再谈谈HashMap的扩容机制,默认大小是多少?什么是负载因子(或填充比)?什么是吞吐临界值(或阈值、threshold)?
HashMap中的重要常量和变量
DEFAULT_INITIAL_CAPACITY: HashMap的默认容量:16
MAXIMUM_CAPACITY: HashMap支持的最大容量:2^30
DEFAULT_LOAD_FACTOR: HashMap的默认加载因子
TREEIFY_THRESHOLD: Bucket中链表长度大于该默认值,转化为红黑树
UNTREEIFY_THRESHOLD: Bucket中红黑树存储的Node小于该默认值,转化为链表
MIN_TREEIF_CAPACITY: 桶中的Node被树化时,最小的hash表容量。(当桶中的Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作,这个MIN_TREEIF_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍)
table:存储元素的数组,总是2的n次幂
entrySet:存储具体元素的集
size:HshMap中存储的键值对的数量
modCount:HashMap扩容和结构改变的次数
threshold: 扩容的临界值 = 容量 * 填充因子
loadFactor: 填充因子
- HashMap常用方法的使用
/*添加、删除、修改
Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
void putAll(Map m):将m中所有的key-value对存放到当前map中
Object remove(Object key):移除指定key的key-value对,并返回value
void clear():清空当前map中的所有数据
*/
puublic class MapTest{
@Test
public void test(){
//put()
Map map = new HashMap();
map.put("AA",123); //添加
map.put("BB",321);
map.put("CC",456);
map.put("AA",654); //修改
System.out.println(map);//{AA=654,CC=456,BB=321}
Map map1 = new HashMap();
map.put("DD",321);
map.put("EE",321);
//putAll()
map.putAll(map1);
System.out.println(map);//{AA=654,CC=456,DD=321,EE=321,BB=321}
//remove()
Object value = map.remove("CC");
System.out.println(map);
System.out.println(value);
//clear()
map.clear();
System.out.println(map.size());
}
}
/*查询
Object get(Object key):获取指定key对应的value
boolean containsKey(Object key):判断是否包含指定的key
boolean containsValue(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集合
*/
Set keyset = map.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
Systemm.out.println(iterator.next());
}
Collection values = map.values();
for(Object obj : values){
System.out.println(obj);
}
//遍历所有的key-value
//方式一:
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while(iterator1.hasNext()){
Object obj = iterator1.next();
Map.entry entry = (Map.entry)obj;
System.out.println(entry.getKey() + "--->" + entry.getValue());//getKey()和getValue是Map的内部接口Entry的抽象方法
}
//方式二:
Set set = map.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
Object key = iterator.next();
Object value = map.getKey(key);
Systemm.out.println(key + "=====" + value);
}
- 总结
添加:put(Object key,Object value)
删除:remove(Object key)
修改:put(Object key,Object value)
查询:get(Object key)
长度: size()
遍历:keySet() / values() /entrySet()
- TreeMap
- 向TreeMap中添加key-value,要求key必须是同一个类的对象,因为要按照key进行排序:自然排序、定制排序
//自然排序
@Test
public void test(){
TreeMap map = new TreeMap();
User u1 = new User("Tom",23);
User u2 = new User("Jerry",24);
User u3 = new User("Jack",20);
User u4 = new User("Rose",18);
map.put(u1,98);
map.put(u2,88);
map.put(u3,78);
map.put(u4,100);
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while(iterator1.hasNext()){
Object obj = iterator1.next();
Map.entry entry = (Map.entry)obj;
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
//定制排序
@Test
public void test(){
TreeMap map = new TreeMap(new Comparator(){
@Override
public int compare(Object o1,Object o2){
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return Integer.compare(u1.getAge(),u2.getAge());
}
throw new RunTimeException("输入的类型不匹配!");
}
});
User u1 = new User("Tom",23);
User u2 = new User("Jerry",24);
User u3 = new User("Jack",20);
User u4 = new User("Rose",18);
map.put(u1,98);
map.put(u2,88);
map.put(u3,78);
map.put(u4,100);
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while(iterator1.hasNext()){
Object obj = iterator1.next();
Map.entry entry = (Map.entry)obj;
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
- HashTable不用了,关心的是它的子类Properties
- Properties用来处理配置文件,key和value都是String类型
Collections工具类
- Collections是一个操作Set、List和Map的工具类
- Collections中提供了一些静态方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变,对集合对象实现同步控制等方法
- 排序操作:
reverse(List):反转List中元素的顺序
shuffle(List):对List集合元素进行随机排序
sort(List):根据元素的自然顺序对List集合元素按升序排序
sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
swap(List,int,int):将List集合中i处元素和j处元素进行交换
Object max(Collection):根据元素的自然排序,返回给定集合中的最大元素
Object min(Collection):根据元素的自然排序,返回给定集合中的最小元素
Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
Object min(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最小元素
int frequency(Collection,Object):返回指定集合中指定元素出现的次数
void copy(List dest,List src):将src中的内容复制到dest中
boolean replaceAll:(List list,Object oldVal,Object newVal)
@Test
public void test(){
List list = new ArrayList();
list.add(123);
list.add(43);
list.add(3);
list.add(-99);
list.add(100);
//List dest = new ArrayList();
//Collections.copy(dest,list);//Source does not fit in dest
List dest = Arrays.asList(new Object[list.size()]);
System.out.println(dest.size());
Collections.copy(dest,list);
System.out.println(dest);
}
Collections类中还提供了多个synchronizedXxx()方法
这些方法可以将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题