1.Set接口
1.1Set接口的
- )Set集合中的元素不可以重复 – 常用来给数据去重
- )元素无序、无下表且不允许重复,注意:只能存放0-1个null值
- )HashSet : 底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K,存入内部的HashMap中。当然K仍然不许重复。
- )TreeSet : 底层是TreeMap,也是红黑树的形式,便于查找数据
1.2Set接口集合的常用方法
1)Set接口集合的常用方法继承自Collection集合的常用方法,可以做集合的交集,并集,差集
2)Set接口集合的遍历/迭代的方式只有iterator()
练习:Set接口集合的常用方法以及迭代
package cn.tedu.collection;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/*测试Set接口常用方法*/
public class TestSet {
public static void main(String[] args) {
//1.创建Set集合多态对象
Set<String> set = new HashSet<>();
//2.set集合中存入数据
set.add("牛气冲天");//添加元素
set.add("牛气冲天");
set.add("牛气冲天");
set.add("虎虎生威");
System.out.println(set);//[虎虎生威, 牛气冲天],无序且不能重复
/*1.set集合中的元素都是无序
* 2.元素不能重复
* 3.set集合可以存放null值,也只允许存0-1个null值*/
set.add(null);
set.add("null");
System.out.println(set);//[null, 虎虎生威, null, 牛气冲天]
//3.set常用方法测试
//set.clear();//清空集合
System.out.println(set.contains("小脑斧"));//false,判断集合是否包含指定元素
System.out.println(set.isEmpty());//false,判断集合是不是空集合
System.out.println(set.hashCode());//哈希码值
System.out.println(set.size());//4,获取集合的元素个数
System.out.println(set.equals("虎虎生威"));//比较集合对象与指定元素是否相等
System.out.println(set.remove("null"));//移除
System.out.println(set.remove(null));//移除
System.out.println(Arrays.toString(set.toArray()));//将集合转成数组
//4.集合之间的测试
Set<String> set1 = new HashSet<>();
set1.add("小狮子");
set1.add("小海豚");
set1.add("小兔子");
set1.add("小脑斧");
System.out.println(set1);//[小海豚, 小狮子, 小兔子, 小脑斧]
System.out.println(set.addAll(set1));//添加集合
System.out.println(set.containsAll(set1));//包含集合
System.out.println(set);//[虎虎生威, 小海豚, 小狮子, 小兔子, 牛气冲天, 小脑斧]
/*retainAll(),取两个集合的交集【公共部分】
* 需要注意:谁调用就影响谁*/
System.out.println(set.retainAll(set1));//取交集
System.out.println(set);//[小海豚, 小狮子, 小兔子, 小脑斧]
System.out.println(set1);//[小海豚, 小狮子, 小兔子, 小脑斧]
//Set集合迭代器只能用iterator()
//1.获取迭代器
Iterator<String> it = set.iterator();
//2.在循环中判断是否有下一个可以迭代的元素
while(it.hasNext()){
//3.获取本轮循环中迭代到的元素
String next = it.next();
System.out.println(next);
}
}
}
2.HashSet
2.1概念
底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K存入内部的HashMap中,其中K不允许重复,允许使用null
2.2HashSet接口的特点
1)和父类Set特点一样,无序且不允许重复
2)常用方法也继承自Set接口
3)迭代也继承Set接口的迭代方法,iterator()
练习:HashSet接口方法以及迭代的使用
package cn.tedu.collection;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
/*HashSet常用方法以及迭代方法测试*/
public class TestHashSet {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(100);
set.add(200);
set.add(300);
set.add(400);
set.add(400);
set.add(null);
//HashSet()无序且不允许重复,允许存入null0-1个
System.out.println(set);//[400, 100, 200, 300]
//常用方法测试
System.out.println(set.contains(100));//true
System.out.println(set.isEmpty());//false
System.out.println(set.size());//5
System.out.println(set.remove(400));
System.out.println(set);
System.out.println(set.equals(null));//false
System.out.println(Arrays.toString(set.toArray()));//集合转成数组并查看
//集合间的操作
HashSet<Integer> it1 = new HashSet<>();
it1.add(400);
it1.add(500);
it1.add(600);
it1.add(600);
it1.add(null);
System.out.println(it1);
System.out.println(set.addAll(it1));//true
System.out.println(set);
System.out.println(set.contains(it1));
System.out.println(set.containsAll(it1));
System.out.println(set);
System.out.println(set.retainAll(it1));//取交集
System.out.println(set);
// System.out.println(set.removeAll(it1));//移除
// System.out.println(set);
System.out.println(set.clone());
//迭代方式
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
Integer next = it.next();
System.out.println(next);
}
}
}
3.Map接口
1)Map接口与Collection接口无关
2)Map接口格式:
Entry---键值对--映射关系
类型参数:K--表示此映射所维护的键,V--表示此映射所维护的对应的值,也叫哈希表/散列表;常用于键值对结构的数据,其中键不能重复,值可以重复
注意:实际原因中,KEY值不一定只是Integer类型,VALUE也不一定只是String类型
Map接口以键值对Entry的方式存数据
3.1Map接口的特点
1)Map可以根据键来提取对应的值
2)Map的键(KEY)不允许重复,如果重复,对应的值(VALUE)会被覆盖
3)Map存放的都是无序的数据,只能存放0-1个null值
4)Map的初始容量是16,默认的加载因子是0.75,达到容量的75%时开始扩容,按照2的次幂进行扩容
5)决定Map结构的查询性能的两个因素:
初始容量:16--数组的初始长度
加载因子:0.75--数组的数据存入程度
TIPS:
- 扩容只和数组存入数据的程度相关,与链表无关
- 不要将初始容量设置的太高--桶的数目太多,不好迭代
- 不要将加载因子设置的太低,太容易达到扩容的程度,频繁扩容,频繁rehash【重建内部数据结构】,效率拉低
6)hashmap头插法,尾插法
java8使用的是尾插法,头部还是最原始的kv值
3.2继承结构
3.3Map常用方法
Map常用方法 | |
put() | 添加集合元素 |
containsKey(9527) | 判断map是否包含指定KEY |
containsValue("沙悟净") | 判断map是否包含指定VALUE |
get(9529) | 根据KEY获取对应的VALUE |
remove(9528) | 移除指定元素,K-V均删除 |
values() | 把map中所有的vlaue取出放入values集合中 |
注意:map可以使用Collection部分常用方法 |
练习:map常用方法以及特有方法
package cn.tedu.collection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/*测试Map接口*/
public class TestMap {
public static void main(String[] args) {
//1.创建Map多态对象
/*Map中的数据要符合映射规则,一定注意要同时指定K和V的数据类型
* 至于K和V要指定成什么类型,取决于业务*/
Map<Integer, String> map = new HashMap<>();
//2.常用方法测试
map.put(9527,"白骨精");//向集合中添加数据
map.put(9528,"黑熊精");
map.put(9528,"玉兔精");//值不能重复,否则就会被覆盖
map.put(9529,"鲤鱼精");
System.out.println(map);
/*1.Map中存放的都是无序的数据
* 2.Map中的key值不可以重复,否则key对应的value就会被新值覆盖
* 例如:{9527=白骨精, 9528=玉兔精, 9529=鲤鱼精},玉兔精覆盖了黑熊精*/
//3.测试其他常用方法
//map.clear();//清空集合
System.out.println(map.containsKey(9527));//true,判断map是否包含指定KEY
System.out.println(map.containsValue("沙悟净"));//false,判断map是否包含指定VALUE
System.out.println(map.get(9529));//鲤鱼精,根据KEY获取对应的VALUE
System.out.println(map.remove(9528));//玉兔精,移除指定元素,K-V均删除
System.out.println(map.get(9528));//null
System.out.println(map.containsKey(9528));//false
System.out.println(map.size());//2,获取map中键值对的个数
System.out.println(map.hashCode());//获取map对象的hash码值
System.out.println(map.equals("黑熊精"));//false,比较
Collection<String> values = map.values();//把map中所有的vlaue取出放入values集合中
System.out.println(values);//[白骨精, 鲤鱼精]
System.out.println(map.keySet());//[9527, 9529],获取map中KEY值
System.out.println(map.entrySet());//[9527=白骨精, 9529=鲤鱼精],获取map中K-V值
}
}
3.4Map的迭代方式
Map本身没有迭代器,使用的是Set的iterator();
两种方式:
前提:map本身没有迭代器,所以需要转成其他集合进行迭代
方案一:Set keySet()--将map中所有key值取出存入set集合
方案二:Set> entry()
- 把map中一对Key&Value取出,形成一个个Entry
- 将Entry作为一个个独立的元素存入set中
练习:Map的迭代方式的使用
package cn.tedu.map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*测试Map的迭代方法*/
public class TestMap {
public static void main(String[] args) {
//1.创建多态对象
// Map map = new Map();
Map<Integer,String> map = new HashMap<>();
//2.存入数据
map.put(9527,"白骨精");//添加元素
map.put(9528,"黄毛怪");
map.put(9529,"狮子精");
map.put(9530,"金角大王");
System.out.println(map);
/*前提:map本身没有迭代器,所以需要转成其他集合进行迭代
* 方案一:Set<Key> keySet()--将map中所有key值取出存入set集合
* 方案二:Set<Entry<K,V>> entry()
* --把map中一对Key&Value取出,形成一个个Entry<K,V>
*将Entry作为一个个独立的元素存入set中*/
//方案一:
//1.将map中的所有key值取出,存入set集合中,set集合的泛型就是key的类型
Set<Integer> keySet = map.keySet();
//2.遍历集合,需要获取集合对应的迭代器
Iterator<Integer> it = keySet.iterator();
//3.循环遍历集合中的每一个元素
while(it.hasNext()){
Integer key = it.next();
String value = map.get(key);//map集合方法获取指定key值对应的value值
System.out.println("{"+key+"="+value+"}");
}
System.out.println("方式二:");
//方式2:转成Set集合
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
//1.获取迭代器
Iterator<Map.Entry<Integer, String>> it2 = entrySet.iterator();
//2.循环遍历集合中的元素
while(it2.hasNext()){
Map.Entry<Integer, String> entry = it2.next();
Integer key = entry.getKey();//使用Map.Entry()中的方法获取key值
String value = entry.getValue();//使用Map.Entry()中的方法获取value值
System.out.println("{"+key+"="+value+"}");
}
}
}
4.HashMap
- HashMap的键要同时重写hashCode()和equlas()
- hashCode()用来判定二者的hash值是否相同,重写后根据属性生成
- equlas()用来判断属性的值是否相同,重写后,根据属性判断
- ---equlas()判断数据如果相等,hashCode()必须相同
- ---equlas()判断数据如果不等,hashCode()尽量不同
4.1如何确定元素存放的位置上
- HashMap底层是一个Entry[ ]数组(数组+链表/红黑树),当存放数据时,会根据hash算法来计算数据的存放位置
- 数组+链表:当链表长度>8,转成红黑树;
- 数组+红黑树:当链表长度<6时转成链表
- hashMap是否扩容由容量和加载因子共同作用
- 算法:hash(key)%n , n就是数组的长度,其实也就是集合的容量
- 当计算的位置没有数据的时候,会直接存放数据
- 当计算的位置,有数据时,会发生hash冲突/hash碰撞,解决的办法就是采用链表的结构,在数组中指定位置处已有元素之后插入新的元素(尾插法),也就是说数组中的元素都是最早加入的节点
练习:统计输入的字符串出现的次数
package cn.tedu.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/*练习集合相关操作*/
//需求:提示并接收用户输入的一串字符,并统计每个字符出现的次数
public class TestMap3 {
public static void main(String[] args) {
//1.提示并接收用户输入要统计的字符串
System.out.println("请输入您要统计的字符串:");
String input =new Scanner(System.in).nextLine();
//2.指定map结构来存储数据
/*因为map的k-v具有映射关系,对应字符与字符出现的次数,符合业务需求
* 字符是不允许重复的,所有作为KEY,是Character类型
* 字符出现的次数是可以重复的,作为Value,是Integer类型*/
Map<Character,Integer> map = new HashMap<>();
//3.获取到用户输入的每一个字符
/*String类底层维护的是char[]数组,有下标*/
for (int i = 0;i<input.length();i++){
char key = input.charAt(i);//获取指定下标对应的字符
System.out.println("获取到的第"+(i+1)+"个字符"+key);
//4.统计每个字符出现的次数,存到map里
Integer value = map.get(key);//获取指定的key对应的value值
if (value == null){//如果第一次出现,次数还是默认值null
map.put(key,1);//就存入:本字符key,次数是1
}else{//如果不是第一次出现
map.put(key,value+1);//就存入:本字符key,次数是原有值加1
}
}
System.out.println("多个字符出现的个数为:");
System.out.println(map);
}
}
5.map转list对象方法,通过stream或者iterator.key集合转list,values集合转list
// key 转 List
List<Integer> keyList = new ArrayList<>(map.keySet());
List<Integer> keyList2 = map.keySet().stream().collect(Collectors.toList());
// value 转 List
List<String> valueList = new ArrayList<>(map.values());
List<String> valueList2 = map.values().stream().collect(Collectors.toList());
// Iterator转List
List<KeyValue> keyValueList = new ArrayList<>();
Iterator<Integer> it = map.keySet().iterator();
while (it.hasNext()) {
Integer k = (Integer) it.next();
keyValueList.add(new KeyValue(k, map.get(k)));
}
// Java8 Stream
List<KeyValue> list = map.entrySet().stream().map(c -> new KeyValue(c.getKey(), c.getValue())).collect(Collectors.toList());
业务场景转ICEDMemberVO对象:
方法一通过stream:
List<ICEDMemberVO> result = icedMemberManagementVOS.entrySet().stream().map(c -> new ICEDMemberVO(c.getKey(), c.getValue())).collect(Collectors.toList());
方法二,迭代
List<ICEDMemberVO> result = new ArrayList<>();
Iterator<Map.Entry<Integer, List<ICEDMemberManagementVO>>> iterator = icedMemberManagementVOS.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<Integer, List<ICEDMemberManagementVO>> next = iterator.next();
ICEDMemberVO icedMemberVO = new ICEDMemberVO(next.getKey(), next.getValue());
result.add(icedMemberVO);
}
对象实体类:
@Data
public class ICEDMemberVO {
//**成员id**//
private Integer userId;
/**内容**/
List<ICEDMemberManagementVO> icedMemberManagementVOS;
public ICEDMemberVO(Integer key, List<ICEDMemberManagementVO> value) {
this.userId = key;
this.icedMemberManagementVOS = value;
}
}