Set系列集合、Map集合体系
Set系列集合特点:
无序:存取顺序不一致
不重复:可以去除重复
无索引:没有带索引的方法,所以不能使用普遍for循环遍历,也不能通过索引来获取元素
Set集合实现类特点:
HashSet:无序,不重复,无索引
LinkedHashSet:有序,不重复,无索引
TreeSet:排序、不重复、无索引
Set集合的功能基本上与Collection的API一致
package com.itheima.d1_set; import java.util.HashSet; import java.util.Set; public class SetDemo1 { public static void main(String[] args) { //查看Set系列集合的特点:HashSet LinkedHashSet TreeSet //无序,不重复,无索引 Set<String> sets=new HashSet<>(); sets.add("MySql"); sets.add("MySql"); sets.add("Java"); sets.add("Java"); sets.add("HTML"); sets.add("HTML"); sets.add("SpringBoot"); sets.add("SpringBoot"); System.out.println(sets);//[Java, MySql, HTML, SpringBoot] } }
package com.itheima.d1_set; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; public class SetDemo1 { public static void main(String[] args) { //查看Set系列集合的特点:HashSet LinkedHashSet TreeSet //无序,不重复,无索引 Set<String> sets=new LinkedHashSet<>(); sets.add("MySql"); sets.add("MySql"); sets.add("Java"); sets.add("Java"); sets.add("HTML"); sets.add("HTML"); sets.add("SpringBoot"); sets.add("SpringBoot"); System.out.println(sets);//[MySql, Java, HTML, SpringBoot] } } Set系列集合的特点:
无序、不重复、无索引
Set集合的实现类特点
HashSet无序,不重复,无索引
LinkedHashSet:有序,不重复,无索引
TreeSet:可排序,不重复,无索引
HashSet底层原理:
HashSet集合底层采取哈希表存储的数据
哈希表是一种对于增删改查数据性能都较好的结构
哈希表的组成:
JDK8之前,底层使用数组+链表组成
JDK8之后,底层采用数组+链表+红黑树组成
在了解哈希表之前需要先理解哈希值的概念
哈希值:
是JDK根据对象的地址,按照某种规则算出来的int类型的数值
Object类型的API:
public int hashCode():返回对象的哈希值
对象的哈希值特点:
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的
package com.itheima.d1_set; import java.util.Set; import java.util.TreeSet; /*目标:观察TreeSet对于有值特性的数据如和排序 * 学会使用自定以类型的对象进行指定规则排序*/ public class SetDemo4 { public static void main(String[] args) { Set<Integer> sets=new TreeSet<>();//不重复 无索引 可排序 sets.add(23); sets.add(78); sets.add(19); sets.add(36); System.out.println(sets);//19 23 36 78 Set<String> sets1=new TreeSet<>();//不重复 无索引 可排序 sets1.add("cba");//根据首字母在ASCLL码表排序的 sets1.add("Java"); sets1.add("Abc"); sets1.add("bcs"); System.out.println(sets1);//Abc bcs cba } }
package com.itheima.d1_set; public class Apple implements Comparable<Apple>{ private String name; private String color; private double price; private int weight; @Override public String toString() { return "Apple{" + "name='" + name + '\'' + ", color='" + color + '\'' + ", price=" + price + ", weight=" + weight + '}'; } public Apple() { } public Apple(String name, String color, double price, int weight) { this.name = name; this.color = color; this.price = price; this.weight = weight; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } /** * 方法一:类自定义比较规则 * @param o * @return */ @Override public int compareTo(Apple o) { //按照重量进行比较的 return this.weight-o.weight>=0?1:-1; } }
package com.itheima.d1_set; import java.util.Comparator; import java.util.Set; import java.util.TreeSet; /*目标:观察TreeSet对于有值特性的数据如和排序 * 学会使用自定以类型的对象进行指定规则排序*/ public class SetDemo4 { public static void main(String[] args) { Set<Integer> sets=new TreeSet<>();//不重复 无索引 可排序 sets.add(23); sets.add(78); sets.add(19); sets.add(36); System.out.println(sets);//19 23 36 78 Set<String> sets1=new TreeSet<>();//不重复 无索引 可排序 sets1.add("cba");//根据首字母在ASCLL码表排序的 sets1.add("Java"); sets1.add("Abc"); sets1.add("bcs"); System.out.println(sets1);//Abc Java bcs cba System.out.println("---------------"); Set<Apple> apples=new TreeSet<>(new Comparator<Apple>() { @Override public int compare(Apple o1, Apple o2) { //return o1.getWeight()-o2.getWeight();升序 //return o2.getWeight()-o2.getWeight();//降序 //注意:浮点型建议直接使用Double.compare进行比较 return Double.compare(o1.getPrice(),o2.getPrice()); } });
Set<Apple> apples=new TreeSet<>((o1,o2) -> Double.compare(o2.getPrice(), o1.getPrice()) ); apples.add(new Apple("红富士","红色",9.9,500)); apples.add(new Apple("青苹果","青色",15.9,400)); apples.add(new Apple("黄苹果","黄色",17,450)); apples.add(new Apple("绿苹果","绿色",29.7,400)); System.out.println(apples);//[Apple{name='青苹果', color='青色', // price=15.9, weight=300}, Apple{name='绿苹果', color='绿色', // price=29.7, weight=400}, Apple{name='黄苹果', color='黄色', // price=17.0, // weight=450}, Apple{name='红富士', color='红色', price=9.9, // weight=500}] } }
TreeSet集合的特点是怎样的?
可排序,不重复,无索引
底层基于红黑树实现排序,增删改查性能较好
TreeSet集合自定义排序桂希恩有几种方式?
2种
类实现Comparable接口,重写比较规则
集合自定义Comparable比较器对象,重写比较规则
可变参数:
可变参数用在形参中可以接受多个数据
可变参数的格式:数据类型...参数名称
可变参数的作用:
传输参数非常灵活,方便。可以不传参数,可以传输1个或者多个,也可以传输一个数组
斗地主游戏:
package com.itheima.d3_coolection_test; public class Card { private String size; private String color; private int index; public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } @Override public String toString() { return size+color; } public Card() { } public Card(String size, String color,int index) { this.size = size; this.color = color; this.index=index; } public String getSize() { return size; } public void setSize(String size) { this.size = size; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } }
package com.itheima.d3_coolection_test; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class GameDemo { /*定义一个静态的集合存储54张牌对象*/ public static List<Card> allCards=new ArrayList<>(); //作牌:定义静态代码块初始化牌的数据 static{ //3.定义点数:小数确定,类型确定,使用数据 String[] sizes={"3","4","5","6","7","8","9","10","J","Q","K","A","2"}; //定义花色,个数确定,类型确定,使用数组 String[] colors={"♦","♥","♣","♠"}; //综合点数和花色 int index=0; for(String size:sizes){ index++; for(String color:colors){ //封装成一个牌对象 Card c=new Card(size,color,index); //存入到集合容器中去 allCards.add(c); } } //大小王存入到集合对象中去 Card c1=new Card("","🃏",++index); Card c2=new Card("","🃏",++index); Collections.addAll(allCards,c1,c2); System.out.println("新牌:"+allCards); } public static void main(String[] args) { //9.洗牌 Collections.shuffle(allCards); System.out.println("洗牌后:"+allCards); //10:发牌:定义三个玩家,每个玩家的拍色也是一个集合容器 List<Card> linghuchong=new ArrayList<>(); List<Card> jiumozhi=new ArrayList<>(); List<Card> renyingying=new ArrayList<>(); //11.开始发牌,从牌集合中发出51张牌给三个玩家,剩余3张作为底牌 for (int i = 0; i < allCards.size()-3; i++) { //先拿到当前牌对象 Card c=allCards.get(i); if(i%3==0){ linghuchong.add(c); }else if(i%3==1){ jiumozhi.add(c); }else if(i%3==2){ renyingying.add(c); } } //拿到最后三张底牌 List<Card> lastThreeCards=allCards.subList(allCards.size()-3,allCards.size()); //给玩家的牌排序(从大到小 可以自己先试一试) sortCards(linghuchong); sortCards(jiumozhi); sortCards(renyingying); //输出玩家的牌 System.out.println("啊冲:"+linghuchong); System.out.println("啊久:"+jiumozhi); System.out.println("盈盈:"+renyingying); System.out.println("三张底牌:"+lastThreeCards); } //给牌排序 private static void sortCards(List<Card> cards) { Collections.sort(cards, new Comparator<Card>() { @Override public int compare(Card o1, Card o2) { return o2.getIndex()- o1.getIndex(); } }); } }
Map集合概述和使用:
Map集合是一种双列集合,每个元素包含两个数据
Map集合的每个元素的格式:key=value(键值对元素)
Map集合也称为"键值对集合"
Map集合整体格式:
Collection集合的格式:[元素1,元素2,元素3...]
Map集合的完整格式:[key1=value1,key2=value2,key3=value3,.....]
Map集合的使用场景之一:
购物车提供的四个商品和购买的数量在后台需要容器存储
每个商品对象都一一对应一个购买数量
把商品对象看成是Map集合的键,购买数量看成Map集合的值
{商品1=2,商品2=3,商品3=4,商品4=3}
Map集合是什么?使用场景是什么样的?
Map集合是键值对集合
Map集合非常适合做类购物车这样的业务场景
Map集合体系特点:
Map集合的键无序,不重复的 Map集合的值不做要求可以重复
Map集合体系特点:
Map集合的特点都是由键决定的
Map集合的键是无序的,不重复的,无索引的,只可以不做要求(可以重复)
Map集合后面重复的键对应的值会覆盖前面重复的键
Map集合的键值对都可以为null
Map集合实现类特点:
HashMap:元素按照键是无序,不重复,无索引,值不做要求(与Map体系一致)
package com.itheima.d5_map; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; //识别Map体系的特点:按照键无序,不重复,无索引,值不做要求 public class MapDemo1 { public static void main(String[] args) { //创建一个Map集合对象,maps添加的方式是put //Map<String, Integer> maps = new HashMap<>(); Map<String,Integer> maps=new LinkedHashMap<>(); maps.put("鸿星尔克",3); maps.put("枸杞",1); maps.put("Java",100); maps.put("枸杞",100); maps.put(null,null);//如果前面的键与后面的键相同,那么后面的值将覆盖前面的值 System.out.println(maps);//{鸿星尔克=3, 枸杞=100, Java=100, null=null} } }
Map集合的特点:
HashMap:元素按照键是无序,不重复,无索引,值不做要求(与Map体系一致)
LinkedHashMap:元素按照是有序,不重复,无索引,值不做要求
TreeMap:元素按照键是排序,不重复的,无索引的,值不做要求
Map集合:
Map是双列集合的祖宗接口,他的功能是全部双列集合都可以继承使用的
package com.itheima.d5_map; import java.util.*; public class MapDemo2 { public static void main(String[] args) { //1.添加元素:无序,不重复,无索引 Map<String, Integer> maps = new HashMap<>(); maps.put("iphoneX",10);//Map集合后面重复的键对于的元素会 // 覆盖前面重复的个数 maps.put("娃娃",31); maps.put("iphoneX",100); maps.put("huawei",100); maps.put("生活用品",10); maps.put("手表",102); System.out.println(maps); //2.清空集合 //maps.clear(); //System.out.println(maps); //3.判断集合是否为空,为空返回true,反之 //System.out.println(maps.isEmpty()); //4.根据键获取对应值:public V get(Object key) Integer key=maps.get("huawei"); System.out.println(key); System.out.println(maps.get("生活用品")); System.out.println(maps.get("你好")); //5.根据键删除整个元素(删除键会返回键的值) System.out.println(maps.remove("iphoneX")); System.out.println(maps); //6.判断是否包含某个键,包含返回true.反之 System.out.println(maps.containsKey("娃娃")); System.out.println(maps.containsKey("iphoneX")); //7.判断是否包含某个值 System.out.println(maps.containsValue(10)); System.out.println(maps.containsValue(100)); //8.获取全部键的集合,public Set<K> keySet() Set<String> keys=maps.keySet(); System.out.println(keys); System.out.println("-----------------"); //9.获取全部值的集合,Collection<V> values Collection<Integer> values=maps.values(); System.out.println(values); //10.集合的大小 System.out.println(maps.size()); //11.合并其他Map集合(拓展) Map<String,Integer> map1=new HashMap<>(); map1.put("java1",1); map1.put("java2",100); map1.put("java2",101); Map<String, Integer> map2 = new HashMap<>(); map2.put("java2",1); map2.put("java3",100); map1.putAll(map2); System.out.println(map1); System.out.println(map2); } } Map集合的遍历方式一:键找值
package com.itheima.d5_map; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo3 { public static void main(String[] args) { Map<String,Integer> maps=new HashMap<>(); maps.put("娃娃",30); maps.put("iphoneX",100); maps.put("huiwei",1000); maps.put("生活用品",10); maps.put("手表",10); System.out.println(maps); //{手表=10, 生活用品=10, huiwei=1000, iphoneX=100, 娃娃=30} //1.键找值:第一步:先拿到集合的全部键 Set<String> keys=maps.keySet(); //2.第二步:遍历每个键,根据键提取值 for(String key:keys){ //调用maps中的get方法得到键 int value=maps.get(key); System.out.println(key+"==>"+value); } } }
遍历Map集合方式二:键值对
先把Map集合转换成Set集合,Set集合中每个元素都是键值对实体类型了
遍历Set集合,然后提取键以及提取值
package com.itheima.d5_map; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo4 { public static void main(String[] args) { Map<String,Integer> maps=new HashMap<>(); maps.put("娃娃",30); maps.put("iphoneX",100); maps.put("huawei",88); maps.put("生活用品",10); maps.put("手表",10); System.out.println(maps); //Set<Map.Entry<String,Integer>> entries=maps.entrySet(); Set<Map.Entry<String,Integer>> entries=maps.entrySet(); //开始遍历 for (Map.Entry<String,Integer> entry: entries) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + "====>" + value) } } }
Map集合的遍历方式三:lambda
得益于JDK8开始的新技术Lambda表达式。提供了一种更简单,更直接的遍历集合的方式
Map结合Lambda遍历的API
default void forEach(BiConsumer<? super K,? super V>action>) 结合lambda遍历Map集合
package com.itheima.d6_map_test; import java.util.HashMap; import java.util.Map; import java.util.Random; //需求:统计投票人数 public class MapTest1 { public static void main(String[] args) { //1.把80个学生选择的数据拿进来 String[] selects={"A","B","C","D"}; //定义一个StringBuilder的对象 StringBuilder sb=new StringBuilder(); //获取一个随机数对象 Random ra = new Random(); //定义一个循环 for (int i = 0; i < 80; i++) { //用StringBuilder的对象名添加学生,selects添加的数组值为随机数 sb.append(selects[ra.nextInt(selects.length)]); } System.out.println(sb); //定义一个Map集合记录最终统计的结果 A=30 Map<Character ,Integer> infos=new HashMap<>();//{} //3.遍历80个学生选择的数据 for (int i = 0; i < sb.length(); i++) { //提取当前选择 char ch=sb.charAt(i); //判断Map集合中是否存在这个键 if(infos.containsKey(ch)){ infos.put(ch,infos.get(ch)+1); }else{ //说明此经典是第一次统计 infos.put(ch,1); } } //输出集合 System.out.println(infos); } }