Java-集合类

集合类的总认识 

集合中储存的是元素的什么信息

集合中储存的是元素的地址

414cc68d44f24cdcb6b2360800d419d3.png

无序是指先添加的元素跑到后面 ,最终获取的元素顺序与添加的元素顺序不一样

无索引意味着不能使用get(i)方法

7c66828dacd64d5f9dbd9b3d2ad48b71.png

26d4f3220a814b47a3303cbcb3c67853.png

cb3b52e394354a60836f7f6594fb5a0a.png

import java.util.ArrayList;
import java.util.HashSet;

public class CollectionTest1 {
    public static void main(String[] args) {
        //简单确认一下Collection集合的特点
        ArrayList<String> list =new ArrayList<>();
        //有序,可重复,有索引
         list.add("java1");
         list.add("java2");
         list.add("java1");
         list.add("java2");
        System.out.println(list);
        System.out.println("----------------");
        HashSet<String> sets =new HashSet<>();
        //无序,不重复,无索引
        sets.add("java1");
        sets.add("java2");
        sets.add("java1");
        sets.add("java3");
        System.out.println(sets);

    }
}

Collection 集合

collection的常用方法9个

f1f93293e2274d8cbd7bc1ba893924f3.png

 1.add方法,添加元素,添加成功返回true 



 //多态
        Collection<String>  c =new ArrayList<>();
             c.add("java2");
        System.out.println(c.add("java1"));//ture
        c.add("java3");
        c.add("java1");
        c.add("java2");

 2.claer 清空集合数据 

   //2.claer 清空集合数据
        c.clear();
        System.out.println(c);
        c.add("java3");
        c.add("java1");
        c.add("java2");

    3. isEmpty判断集合是否为空,为空返回true。反之false

   //3. isEmpty判断集合是否为空,为空返回true。反之false
        c.clear();
        System.out.println(c.isEmpty());//true
        c.add("java3");
        c.add("java1");
        c.add("java2");
        System.out.println(c.isEmpty());

 4.size()获取集合大小
 5.contains()判断集合中是否包含某个元素 

  //4.size()获取集合大小
        System.out.println(c.size());
        //5.contains()判断集合中是否包含某个元素
        System.out.println(c.contains("java1"));//true
        System.out.println(c.contains("java"));//false

6.remove 删除某个元素,如果有多个重复元素,默认删除第一个元素 

 //6.remove 删除某个元素,如果有多个重复元素,默认删除第一个元素
        c.add("java1");
        System.out.println(c);
        System.out.println(c.remove("java1"));
        System.out.println(c);

7.toArray 把集合转换成数组
        用Object类型接数据,原因为虽然使用泛型,String。但是由于泛型在运行阶段已经擦除了
      用Object接使得数据更全面 

   //7.toArray 把集合转换成数组
        //用Object类型接数据,原因为虽然使用泛型,String。但是由于泛型在运行阶段已经擦除了
        //用Object接使得数据更全面
        Object[]arr = c.toArray();
        System.out.println(Arrays.toString(arr));

8.指定类型数组(保证添加的元素全为字符串) 

  //指定类型数组(保证添加的元素全为字符串)
        String [] arr2 =c.toArray(new String[c.size()]);
        System.out.println(Arrays.toString(arr2));

9.addAll把一个集合的全部数据倒进另一个集合中去(保证类型相同) 

   //addAll把一个集合的全部数据倒进另一个集合中去(保证类型相同)
        Collection<String> c1 =new ArrayList<>();
        c1.add("java3");
        c1.add("java1");
        c1.add("java2");
        Collection<String> c2 =new ArrayList<>();
        c2.add("java5");
        c2.add("java6");
        c2.add("java7");
        //把c2放入c1中
        c1.addAll(c2);
        System.out.println(c1);
        System.out.println(c2);

Collection遍历方式 

迭代器(Iterator)

86fefaf6a32b43cd900df5f713c3c352.png

  Collection<String> c = new ArrayList<>();
   Iterator<String> it = c.iterator();
 while (it.hasNext()) {

            String ele = it.next();
            System.out.print(ele);
        }
//使用迭代器遍历
public class CollectionDemo1 {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<>();
        c.add("赵敏");
        c.add("小昭");
        c.add("素素");
        c.add("灭绝");
        System.out.println(c);
        //使用迭代器遍历集合
        //1.从集合对象中获取迭代器对象
        Iterator<String> it = c.iterator();
        System.out.println(it.next());
        System.out.println(it.next());
        System.out.println(it.next());
        System.out.println(it.next());
        // System.out.println(it.next());//报错原因超范围了
        //2.我们应该使用循环迭代集合
        while (it.hasNext()) {

            String ele = it.next();
            System.out.print(ele);
        }

增强for循环

81717499ed4245f8816c5ebf9d33dd10.png

   3,增强for循环
      for (String ele1 : c) {
         System.out.println(ele1);
       }
      for (String s : c) {

       }

快捷键c.for直接进行打印c
for (String s : c) {
    
}

lambda表达式 

    System.out.println("----------------");
        c.forEach(s -> System.out.println(s));

        c.forEach(System.out::println);

0a9651bd7b4340b4bd88a90f8081a003.png

List集合

List集合特点是有序,可重复,有索引 

 List<String> list =new ArrayList<>(); 

ArrayList与LinkedList有什么区别 

ArrayList

查询快,增删慢

LinkedList 

查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的 

总结

  • ArrayList:

    • 随机访问:由于底层是数组,支持 O(1) 时间复杂度的随机访问操作。
    • 插入和删除:在数组中间插入或删除元素会导致元素的移动,时间复杂度为 O(n)。尾部插入(如果不需要扩展数组)为 O(1)。
  • LinkedList:

    • 随机访问:需要遍历链表来访问元素,时间复杂度为 O(n)。
    • 插入和删除:在链表的头部或尾部插入或删除元素为 O(1) 时间复杂度;在链表中间插入或删除元素也为 O(1),但需要先定位到插入点,定位操作为 O(n)。
  • ArrayList:适合频繁的随机访问,但在插入和删除操作时可能效率较低。
  • LinkedList:适合频繁的插入和删除操作,但在随机访问时效率较低。

List<String> list = new ArrayList<>();

 list = new LinkedList<>(list); 

实现将list转化为LinkedList

创建了一个新的 LinkedList 实例,并将 ArrayList 中的元素复制到这个新的 LinkedList 中。

784ee352614949b3adc74e5df38480f2.png

 1.add(int index, E element) 在某个索引位置插入元素前面
        

  List<String> list =new ArrayList<>();
        list.add("赵敏");
        list.add("小昭");
        list.add("素素");
        list.add("灭绝");
        System.out.println(list);
        //1.add(int index, E element) 在某个索引位置插入元素
        list.add(2,"加入到素素前面元素");
        System.out.println(list);

2.remove 根据索引删除数据,并且返回删除元素 

 //2.remove 根据索引删除数据,并且返回删除元素
        System.out.println(list.remove(2));//加入到素素前面元素

3.get  返回集合中指定位置的元素 

 //3.get  返回集合中指定位置的元素
        System.out.println(list.get(1));//小昭

4.set  修改索引位置元素,修改成功后,会返回原来的数据 

 //4.set  修改索引位置元素,修改成功后,会返回原来的数据
        System.out.println(list.set(3, "牛魔王"));//灭绝
        System.out.println(list);//[赵敏, 小昭, 素素, 牛魔王]

四种循环 

package com.itheima.d3_list;

import javax.swing.text.html.HTMLDocument;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListTest2 {
    public static void main(String[] args) {
        List<String> list =new ArrayList<>();
        list.add("赵敏");
        list.add("小昭");
        list.add("素素");
        list.add("灭绝");
        //for循环
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        //迭代器
        Iterator<String> it  =list.iterator();
        while (it.hasNext())
        {
            System.out.println(it.next());

        }
        //增强for循环
        for (String s : list) {
            System.out.println(s);
        }
        //lambda表达式
        list.forEach(s-> System.out.println(s));
    }
}

c54cb2ac66004eae825d7ed2860937e6.png

ArrayList集合的底层原理  

查询快,增删慢 

377566b9ac4b4212b81ff3904cb45f73.png

28b284422d654b6f836401a10f9fcc47.png

 链表的简单认识

65670a6cc748445c9d306330e7ed24d4.png

4c275c74d9f3459aabd0784a5eb66e60.png

7d92a4af326d49cc84211e076419bc51.png

LinkedList集合的底层原理 

查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的 

f9c7c7e7cc044b23ac41851014698387.png

LinkedList的特有方法 

4b4d82cdfcd74930b3ffe3adcacf9da1.png

275c5f871c914f16935e8b8eb9c61e39.png

package com.itheima.d3_list;

import java.util.LinkedList;

//案例
public class ListTest3case {
    public static void main(String[] args) {
        //创建一个对列
        LinkedList<String>  quene =new LinkedList<>();
        quene.add("第一个");
        quene.add("第二个");
        quene.add("第三个");
        System.out.println(quene);
        System.out.println("-----------------");
        System.out.println(quene.removeFirst());//第一个
        quene.removeFirst();

        System.out.println(quene);//[第三个]
    }
}

747b464e91b4461cb68b97fbe6cb9c0b.png

push相当于addFirst

pop相当于removeFirst 

栈的应用:弹夹 

  //创建一个栈对象
        LinkedList<String> stack =new LinkedList<>();
                //压栈(push)
//        stack.addFirst("第一个子弹");
//        stack.addFirst("第二个子弹");
//        stack.addFirst("第三个子弹");
//        stack.addFirst("第四个子弹");
        stack.push("第一个子弹");
        stack.push("第二个子弹");
        stack.push("第三个子弹");
        stack.push("第四个子弹");

        System.out.println(stack);

        //出栈(pop)
//        System.out.println(stack.removeFirst());
//        System.out.println(stack.removeFirst());
//        System.out.println(stack);
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack);

set集合 

set集合的特点:无序,添加数据的顺序和获取出的数据顺序不一致;不重复,无索引 

cd8fb201a80d4602acff286b717f70c3.png

326cf9d39baf44849114ebddb8ab25d7.png

哈希值的简单认识 

942929a65d97495aa74da6714dcb21d0.png

 SetTest2_Student s1 =new SetTest2_Student("蜘蛛精",25,169.5);
        SetTest2_Student s2 =new SetTest2_Student("紫霞",22,166.5);
        System.out.println(s1.hashCode());//1324119927
        System.out.println(s1.hashCode());//1324119927
        System.out.println(s2.hashCode());//990368553
            //两者哈希值相同
        String  str1= new String("abc");
        String  strr2 =new String( "acD");
        System.out.println(str1.hashCode());//96354
        System.out.println(strr2.hashCode());//96354

HashSet-哈希表

无序,不重复,无索引

 Set<SetTest2_Student> students =new HashSet<>(); 

无序:是指HashSet是通过从前往后依次遍历与HashSet的存入数据的哈希值算法不同。

导致去遍历是无序的 

4c7dc28d24db443da095e7435ce29994.png

f2633321db1b4bf88316cef0beb0fb73.png

如果数组快占满了,就去扩容,默认的加载因子为0.75 去用数组长度去乘于0.752f856f5eb46447248db2b057689aaaaf.png 

b7d195c76b644d45a1bc0993261bb69b.png

二叉树的简单认识 

d0fb8cbbcef54c7181c13eda9813214e.png

规则:小的存左边,大的存右边,一样的不存 

82222832bb9b4f08b7837a8d5fa51e91.png

9d2399236bbb44378edd6449026c2d4e.png

f61942daa654471d9bf248d99708a27c.png

23ae1e30f31b483098fc39458ec7a8c4.png

HashSet去自定义重复的方法 

bf630bf572504f389694e2e7f419248f.png

内容一样的两个学生对象存到HashSet集合中去,不能去重复

原因:HashSet对于创建的不同对象都有不同的哈希值,再拿不同的哈希进行求余得到不同的结果 

如何让HashSet集合实现对内容一样的两个不同对象去重复

重写equals与hasCode方法(用快捷键:generate) 

//只要两个对象内容一样就返回true
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SetTest2_Student that = (SetTest2_Student) o;
        return age == that.age && Double.compare(that.height, height) == 0 && Objects.equals(name, that.name);
    }
//只要两个内容一样就返回一样的哈希值
    @Override
    public int hashCode() {
        return Objects.hash(name, age, height);
    }
public class SetTest2 {
    public static void main(String[] args) {
        Set<SetTest2_Student> students =new HashSet<>();
        SetTest2_Student s1 =new SetTest2_Student("蜘蛛精",25,169.5);
        SetTest2_Student s2 =new SetTest2_Student("紫霞",22,166.5);
        SetTest2_Student s3 =new SetTest2_Student("蜘蛛精",25,169.5);
        SetTest2_Student s4 =new SetTest2_Student("牛魔王",33,178);
System.out.println(s1.hashCode());
        System.out.println(s3.hashCode());
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
            //实现去重复(让两个蜘蛛精对象只保留一个)
        System.out.println(students);
    }
}

LinkedHashSet-双链表

有序,不重复,无索引

LinkedHashSet实现有序通过双链表去完成,在此方法中通过记录前后元素位置

fe33dc495d7044d4b9c04845643f8ce5.png

TreeSet

特点:不重复,无索引,可排序,(默认为升序,按照元素的大小,由小到大排序)

底层是基于红黑树去实现排序的

例如在下面这段代码中。我先加入5让它成为树根,然后去加4,4比5小放左边,再加7,7比5大放在数的右边。再到4,放左边看到重复了就不存了。(图示类似于下图,数据不同)

a133ca44f1ba4d22943c03ae330e1307.png

   Set<Integer> set =new TreeSet<>();
        set.add(5);
        set.add(4);
        set.add(7);
        set.add(4);
        System.out.println(set);//[4, 5, 7]

f9a73267dcda4196aeabd3dc41a28ad1.png

解决TreeSet自定义排序的方法 

联想126节Arrays中自定义排序 

0248c20ace134d57857ed5253f58f34f.png

方式一 

年龄升序

this.age-o.age

年龄降序

o.age-this.age 

比较年龄 

  Set<SetTest2_Student> students =new TreeSet<>();
        students.add(new SetTest2_Student("蜘蛛精",23,145));
        students.add(new SetTest2_Student("紫霞",22,169.8));
        students.add(new SetTest2_Student("至尊宝",23,145));
        students.add(new SetTest2_Student("刘",24,123));

        System.out.println(students);
public class SetTest2_Student implements Comparable<SetTest2_Student>{ 
//this o
    @Override
    public int compareTo(SetTest2_Student o) {
        //如果认为左边的对象大于右边的对象就返回正整数
        //如果左边的对象等于右边的对象就返回0
        //如果左边的对象小于右边的对象就返回负整数
        return this.age-o.age;
    }
}

结果:[SetTest2_Student{name='紫霞', age=22, height=169.8}, SetTest2_Student{name='蜘蛛精', age=23, height=145.0},

SetTest2_Student{name='刘', age=24, height=123.0}] 

 此时自定义按照年龄去排序但是没有至尊宝。原因为至尊宝与蜘蛛精年龄相同就不保存

方式二(比较身高)依旧遵循身高相同只保留一个的思想

  Set<SetTest2_Student> students =new TreeSet<>(new Comparator<SetTest2_Student>() {
            @Override
            public int compare(SetTest2_Student o1, SetTest2_Student o2) {
                //按照身高进行排序
                return Double.compare(o1.getHeight(),o2.getHeight());
            }
        });

简化版

   //身高升序
        Set<SetTest2_Student> students =new TreeSet<>( (o1,o2)-> Double.compare(o1.getHeight(),o2.getHeight()));
        //身高降序
        Set<SetTest2_Student> students1 =new TreeSet<>( (o1,o2)-> Double.compare(o2.getHeight(),o1.getHeight()));

注:当有多个比较规则TreeSet会就近选择一个方法进行比较

下面就会先执行比较身高的方法 

//这是主函数
   Set<SetTest2_Student> students =new TreeSet<>(new Comparator<SetTest2_Student>() {
            @Override
            public int compare(SetTest2_Student o1, SetTest2_Student o2) {
                //按照身高进行排序
                return Double.compare(o1.getHeight(),o2.getHeight());
            }
        });
        students.add(new SetTest2_Student("蜘蛛精",23,145));
        students.add(new SetTest2_Student("紫霞",22,169.8));
        students.add(new SetTest2_Student("至尊宝",23,145));
        students.add(new SetTest2_Student("刘",24,123));
System.out.println(students);



public class SetTest2_Student implements Comparable<SetTest2_Student>{
  //this o
    @Override
    public int compareTo(SetTest2_Student o) {
        //如果认为左边的对象大于右边的对象就返回正整数
        //如果左边的对象等于右边的对象就返回0
        //如果左边的对象小于右边的对象就返回负整数
        return this.age-o.age;
    }
}

ed255f30d8fd4275a5c902d3e862dc17.png

集合的并发修改异常问题

 df9e48f978ed4e589f61a4c0ae225ed8.png

使用增强for循环与lambda表达式是不能修改成功

例子删除名字中有李的名字

 System.out.println("使用迭代器版");
        Iterator<String>  it =list.iterator();
        while (it.hasNext())
        {
            String name =it.next();
            if(name.contains("李"))
            {
//                
                it.remove();
            }

        }
        System.out.println(list);

 it.remove()

删除迭代器当前遍历到的数据,每删除一个数据后
                //相当于在底层进行i-- 

public class CollectionTest1 {
    public static void main(String[] args) {
        //需求:找出名字中有李的并删除
        List<String> list =new ArrayList<>();
        list.add("王麻子");
        list.add("小李子");
        list.add("李爱华");
        list.add("张全蛋");
        list.add("小李");
        list.add("李玉刚");
        System.out.println(list);
//        Iterator<String>  it =list.iterator();
//        while (it.hasNext())
//        {
//            String name =it.next();
//            if(name.contains("李"))
//            {
//                list.remove(name);
//            }
//
//        }
//        System.out.println(list);//会出现异常
        //使用for循环会出现漏删情况
//        for (int i = 0; i < list.size(); i++) {
//                 String name =list.get(i);
//                 if(name.contains("李"))
//                 {
//                     list.remove(name);
//                 }
//
//        }
//        System.out.println(list);
        //修改成功版
        for (int i = 0; i < list.size(); i++) {
            String name =list.get(i);
            if(name.contains("李"))
            {
                list.remove(name);
                i--;
            }

        }
        System.out.println(list);
        System.out.println("使用迭代器版");
        Iterator<String>  it =list.iterator();
        while (it.hasNext())
        {
            String name =it.next();
            if(name.contains("李"))
            {
//                list.remove(name);//并发修改异常的错误
                it.remove();//删除迭代器当前遍历到的数据,每删除一个数据后
                //相当于在底层进行i--
            }

        }
        System.out.println(list);

    }
}

前置知识:可变参数

b7b6fced7a0e4b7caceb01588b3b66a1.png

 

可变参数对外就是参数,对内就是数组。定义在方法或构造器上用于灵活接收数据

可变参数:int..nums 

//认识可变参数
public class paramTest {
    public static void main(String[] args) {
                    test();
                    test(10,11);
                    test(10,34,55,66);
                    test(new int[]{10,20,30,40});
    }

    public  static  void  test( int...nums){
        System.out.println(nums.length);
        System.out.println(Arrays.toString(nums));
        System.out.println("--------------------");

    }
}

注意事项:

1.一个形参列表中,只能有一个可变参数

 报错,形参列表中只能写一个参数

public  static  void  test( int...nums,int...nums2){
        System.out.println(nums.length);
        System.out.println(Arrays.toString(nums));
        System.out.println("--------------------");

    }

2.可变参数必须放在形参列表的最后一个 

787d69eb3d44453eaf902f9aea7df5d8.png

 ef1bd7d45db4472a80209dc7c0461f94.png

Collections 

2343d022294742bca84002feb3dc6dfe.png

1.addAll 为一起collection的集合批量增添数据 

 //1.addAll 为一起collection的集合批量增添数据
        List<String> name =new ArrayList<>();
        Collections.addAll(name,"刘翀羽","宋森康","马俊杰","高晨凯","刘星");
        System.out.println(name);

 2.shuffle  打乱list集合中的元素顺序因为list集合是有序的,其他都是无序的不需要

 //2.shuffle  打乱list集合中的元素顺序因为list集合是有序的,其他都是无序的不需要
          //斗地主应用打乱牌
List<String> name =new ArrayList<>();
        Collections.addAll(name,"刘翀羽","宋森康","马俊杰","高晨凯","刘星");
        System.out.println(name);
          Collections.shuffle(name);
        System.out.println(name);

3.sort对list集合的元素进行升序排序 

注意:sort想要对Set进行排序需要转换

 List<String> list =new ArrayList<>(set);
        Collections.sort(list);
        Set<String> sortedSet = new LinkedHashSet<>(list);

Set<String> set =new LinkedHashSet<>();
        set.add("java");
        set.add("apple");
        set.add("banban");
        List<String> list =new ArrayList<>(set);
        Collections.sort(list);
        Set<String> sortedSet = new LinkedHashSet<>(list);
        System.out.println(sortedSet);

//3.sort对list集合的元素进行升序排序
        List<Integer> list =new ArrayList<>();
        list.add(3);
        list.add(5);
        list.add(2);
        Collections.sort(list);
        System.out.println(list);

4.sort自定义   让Collections对自定义进行排序必须定义规则 

//4.sort自定义   让Collections对自定义进行排序必须定义规则
        //注意:允许年龄重复
            List<Student> students =new ArrayList<>();

            students.add(new Student("蜘蛛精",25,169.5));
        students.add(new Student("紫霞",22,166.5));
        students.add(new Student("蜘蛛精",25,169.5));
        students.add(new Student("牛魔王",33,178));
        Collections.sort(students);
        System.out.println(students);

429eb8998d794fc592de583c45216c25.png

用Comparator接口进行比较(按照身高进行排序) 

  //使用Comparator接口进行比较(按照身高进行排序)
 List<Student> students =new ArrayList<>();

            students.add(new Student("蜘蛛精",25,169.5));
        students.add(new Student("紫霞",22,166.5));
        students.add(new Student("蜘蛛精",25,169.5));
        students.add(new Student("牛魔王",33,178));
         Collections.sort(students, new Comparator<Student>() {
             @Override
             public int compare(Student o1, Student o2) {
                 return  Double.compare(o1.getHeight(),o2.getHeight());
             }
         });
        System.out.println(students);

Collection案例:斗地主

941e56c0d5df47c9ad8a1a08d4041ba9.png

package com.itheima.d8_collection_test;
//目标:斗地主游戏的案例进行开发
        /*案例分析
        业务:总共有54张牌
        点数:3,4,5,6,7,8,9,10,J,Q,K,A,1,2
        花色:
        大小王
        点数分别为要组合四种花色,大小王各一张
        斗地主,发出51张,剩下3张作为底牌
         */
public class GameDemo {
    public static void main(String[] args) {

      //1.牌类
        //2.房间
        Room m =new Room();

        m.start();






    }
}
package com.itheima.d8_collection_test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;

//房间
public class Room {
    //必须有一张牌
    private List<Card> allCards =new ArrayList<>();
    public Room() {
        //1.做出54张牌,存入到Collection集合中
        //a.点数,个数确定了类型也确定、
        String numbers[] = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
        //b.花色,点数确定了,类型确定
        String[] colors = {"♠", "♥", "♣", "♦"};
        int size = 0;//表示每张牌的大小
        //c.遍历点数,在遍历花色,组织牌
        for (String number : numbers) {
                 //number= "3"
            size++;
            for (String color : colors) {
                  //得到一种牌
                Card  c =new Card(number,color,size);
                allCards.add(c);//存入牌
            }
        }
        //单独存入小大王
        Card c1 =new Card("","🃏",++size);
        Card c2 =new Card("","🃏",++size);
        Collections.addAll(allCards,c1,c2);
        System.out.println("新牌"+allCards);
    }
/*
游戏启动
 */
    public void start() {
                //利用shuffle每次洗牌都不一样
            Collections.shuffle(allCards);
        System.out.println("洗牌后"+allCards);
          /*
    2.发牌,首先肯定要定义三个玩家,
    虽然使用Set(TreeSet)可以自动完成升序,但是会使得没有重复牌。
    所以使用List(ArrayList)更方便
     */
        4.看牌
        ArrayList<Card> liuchongyu =new ArrayList<>();
        ArrayList<Card> songsenkang =new ArrayList<>();
        ArrayList<Card> majunjie =new ArrayList<>();
        for (int i = 0; i < allCards.size()-3; i++) {
            Card card= allCards.get(i);
              if(i%3==0){
                  liuchongyu.add(card);
              }
              else if(i%3==1)
              {
                  songsenkang.add(card);
              }
              else if(i%3==2)
              {
                  majunjie.add(card);
              }

        }
        //3.对3位玩家的牌进行排序
        sortCards(liuchongyu);
        sortCards(songsenkang);
        sortCards(majunjie);
        System.out.println("刘翀羽的牌"+liuchongyu);
        System.out.println("宋森康"+songsenkang);
        System.out.println("马俊杰"+majunjie);
        //处理最后三张牌
//        System.out.println(allCards.get(53));
//        System.out.println(allCards.get(52));
//        System.out.println(allCards.get(51));
        List<Card> list = allCards.subList(allCards.size() - 3, allCards.size());
        System.out.println("底牌"+list);
        songsenkang.addAll(list);
   sortCards(songsenkang);
        System.out.println("宋森康抢到地主"+songsenkang);
    }
/*
集中进行排序
 */
    private void sortCards(ArrayList<Card> cards) {
            Collections.sort(cards, new Comparator<Card>() {
                @Override
                public int compare(Card o1, Card o2) {
                    //进行升序牌
                   // return o1.getSize()-o2.getSize();
                    //进行降序牌
                    return o2.getSize()-o1.getSize();
                }
            });
    }


}

package com.itheima.d8_collection_test;
//牌类
public class Card {
    private  String number;
    private  String  color;
    //每张牌有大小
    private  int size;//0 1 2 3 4 ...13

    @Override
    public String toString() {
        return color+number;
    }

    public Card() {
    }

    public Card(String number, String color, int size) {
        this.number = number;
        this.color = color;
        this.size = size;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }
}

结果 

9ef4999a5b6f47cca4b00d5eb4abcfe7.png

Map集合 

map是一个泛型接口

无序是指先添加的元素跑到后面 ,最终获取的元素顺序与添加的元素顺序不一样

无索引意味着不能使用get(i)方法

4c4b5a35ddc14d92a273276de8928c20.png

f0fa6820e62f4695be64e8458ebca179.png

c319e79154cd476494dddcf1506b911c.png

Map<String,Integer>  map =new HashMap<>();

 Map<String,Integer>  map =new HashMap<>();
        //按照键 无序 不重复 无索引
        map.put("手机",12);
        map.put("相机",1);
        map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
        map.put(null,null);
        System.out.println(map);
  Map<String,Integer>  map =new LinkedHashMap<>();
        //按照键 有序 不重复 无索引
        map.put("手机",12);
        map.put("相机",1);
        map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
        map.put(null,null);
        System.out.println(map);
  Map<String,Integer>  map =new LinkedHashMap<>();
        //按照键 有序 不重复 无索引
        map.put("手机",12);
        map.put("相机",1);
        map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
        map.put(null,null);
        System.out.println(map);

 结果

{手机=100, 相机=1, null=null}

 //可排序,不重复,无索引
        Map<Integer,String> map1 =new TreeMap<>();
        map1.put(23,"java");
        map1.put(24,"kobe");
        map1.put(23,"乔丹");
        map1.put(16,"男孩");
        System.out.println(map1);

{16=男孩, 23=乔丹, 24=kobe}

Map集合 

Map的常用方法 11

5ac2d06d3af34613bc324d9c9ec746ee.png

cc8e6d2c774d46728b0a4ee57b146c92.png

2e980efe8fc4424c8866ed00bc25f55b.png

1.put()添加集合 

Map<String,Integer> map =new HashMap<>();
        //按照键 无序 不重复 无索引
        map.put("手机",12);
        map.put("相机",1);
        map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
        map.put(null,null);
        map.put("手表",15);
        System.out.println(map);

2.size() 获取集合的大小 

 //1.size() 获取集合的大小
        System.out.println(map.size());

3.claer() 清空集合 

//2.claer() 清空集合
            //map.clear();
            System.out.println(map);

4.isEmpty  判断集合是否为空,为空返回true反之false 

  //3.isEmpty  判断集合是否为空,为空返回true反之false
        System.out.println(map.isEmpty());

5.get(key)根据键获取值 

//4.get(key)根据键获取值
        System.out.println(map.get("手机"));
        //若键不存在就返回null
        System.out.println(map.get("1"));//null

 6.remove根据键删除某个元素(删除会返回键的值)

 //5.remove根据键删除某个元素(删除会返回键的值)
        System.out.println(map.remove("手表"));//15
        System.out.println(map);

7.containsKey  判断是否包含某个键,包含返回true ,不包含返回false 

8.containsValue  判断是否包含某个值

   //6.containsKey  判断是否包含某个键,包含返回true ,不包含返回false
        System.out.println(map.containsKey("手机"));//true

        //7.containsValue  判断是否包含某个值
        System.out.println(map.containsValue(100));
        //注意类型一致不要字符串
        System.out.println(map.containsValue("100"));

9.set<K> KeySet() 获取Map集合的全部键 

10.Collection<V> values() 获取Map集合的全部值
        不放到Set集合 原因不重复 collection的原因可以重复

8.set<K> KeySet() 获取Map集合的全部键
        Set<String> keys =map.keySet();
        System.out.println(keys);
        //9.Collection<V> values() 获取Map集合的全部值
        //放到Set集合 不重复collection的原因可以重复
        Collection<Integer> values =map.values();
        System.out.println(values);

 11.putAll 把其他Map集合的数据倒入在自己集合中来

10. putAll 把其他Map集合的数据倒入在自己集合中来
        Map<String,Integer> map1 =new HashMap<>();
        map1.put("java1",10);
        map1.put("java2",20);
        Map<String,Integer> map2 =new HashMap<>();
        map2.put("java3",10);
        map2.put("java1",200);//重复留下新加入的
        map1.putAll(map2);
        System.out.println(map1);

  Map的遍历 

6ac79e8b7e3a4a799ffa125d8d4732a5.png

1.键找值 

bb36cd9c3a854e49b385464f3bf9840e.png

public static void main(String[] args) {
        //准备一个map集合遍历数据
        Map<String,Double> map =new HashMap<>();
        map.put("牛魔王",156.4);
        map.put("白蛇传",178.3);
        map.put("白娘子",145.6);
        map.put("牛魔王",178.9);
        System.out.println(map);
        //1.获取map的集合的所有键
        Set<String> keys =map.keySet();
        System.out.println(keys);
        //2.遍历全部的键,根据键来获取其对应的值
        for (String key : keys) {
               double value =map.get(key);
            System.out.println(key+"====>"+value);

        }

2.键找值

调用map集合提供的entrySet方法,把Map集合转化成键值对类型的Set集合
        Set<Map.Entry<String, Double>> entries = map.entrySet(); 

List 可能不太适合 Map 的 entrySet() 主要有以下原因:

唯一性要求:Map 的每个键值对都是唯一的,Set 自带唯一性保证,

而 List 允许重复项,不适合直接表示唯一的键值对。

//1.调用map集合提供的entrySet方法,把Map集合转化成键值对类型的Set集合
        Set<Map.Entry<String, Double>> entries = map.entrySet();
        for (Map.Entry<String, Double> entry : entries) {
            String key =entry.getKey();
           double value=entry.getValue();
            System.out.println(key+"----->"+value);
        }

85cb1b4ae2cd4fdea627d5dea952c4b1.png

 3.lambda表达式

 map.forEach((k,v)->{
            System.out.println(k+"---->"+v);
        });

94f927b9832e48128e67e6499d7b91c2.png

  map.forEach(new BiConsumer<String, Double>() {
            @Override
            public void accept(String k, Double v) {
                System.out.println(k+"----->"+v);
            }
        });
        System.out.println("--------------");
        //简化版
        map.forEach((k,v)->{
            System.out.println(k+"---->"+v);
        });

Map的案例 

e7b6fc5ccdfc4f429db2ec82ec2133ac.png

package com.itmap.d2_map_traverse;

import java.util.*;

public class MapTest4 {
    public static void main(String[] args) {
        List<String> date =new ArrayList<>();
        String [] selects ={"A","B","C","D"};
        Random r =new Random();
        for (int i = 0; i < 80; i++) {
            //生成0,1,2,3四个索引去拿到abcd
            int indiex =  r.nextInt(4);
            date.add(selects[indiex]);
        }
        System.out.println(date);
        //2.开始统计每个景点的投票人数
        //准备一个Map集合用于统计最终的结果
        Map<String,Integer> result =new HashMap<>();
        //3.开始遍历80个景点数据
        for (String s : date) {
                //问问Map集合中是否包含四个景点
               if(result.containsKey(s))
               {
                   //说明这个景点之前统计过,要加一
                   result.put(s, result.get(s)+1);
               }
               else {
                   //说明之前没有统计,再结果对应的值赋值为1
                    result.put(s,1);
               }
        }
        System.out.println(result);

    }
}

HashMap-哈希表

无序,不重复,无索引(用的最多)

63315f40f5cf41e2901c52f86d6de412.png

f23c94fa43ec4cd0bcff05756163f40d.png

7f3b2e75fdd04768a605fcc23e09c553.png7731a10c9ce143ac820645ee8d79ebe6.png 

在下列的代码中出现两个相同的信息(重复)但是由于两者哈希值不一样,要解决必须自定义重写hasCode与equals方法

Map<Student,String> map =new HashMap<>();
        map.put(new Student("刘翀羽",19,175.5),"九班");
        map.put(new Student("宋森康",17,176),"十班");
        map.put(new Student("马俊杰",20,183),"11班");
        map.put(new Student("刘星",21,189),"12班");
        map.put(new Student("刘翀羽",19,175.5),"九班");
        System.out.println(map);

在学生类中增加此行代码(genegrate右键)重新启动代码将出现一个刘翀羽信息 

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Double.compare(student.height, height) == 0 && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, height);
    }

LinkedHashMap-双链表

按照键 有序  不重复 无索引
        Map<String,Integer> map =new LinkedHashMap<>(); 

156783f2e79f4cc7bda7ba348350acb9.png

 //Map<String,Integer> map =new HashMap<>();
          // 按照键 有序  不重复 无索引
        Map<String,Integer> map =new LinkedHashMap<>();
        map.put("手表",100);
        map.put("手表",220);
        map.put("手机",2);
        map.put("Java",2);
        map.put(null,null);
        System.out.println(map);

TreeMap  

特点 :不重复,无索引,可排序(按照键的大小默认升序排序,只能对键排序)

e0077e519df44b1b8684ed4d5d79b62d.png

不进行自定义比较规则会报错,TreeMap会对键排序 

 Map<Student ,String> map =new TreeMap<>();
        map.put(new Student("刘翀羽",19,175.5),"九班");
        map.put(new Student("宋森康",17,176),"十班");
        map.put(new Student("马俊杰",20,183),"11班");
        map.put(new Student("刘星",21,189),"12班");
        map.put(new Student("刘翀羽",19,175.5),"九班");
        System.out.println(map);

解决方法一

让类实现Coparable接口,重写比较规则

其中进行年龄升序排序,记住一定是对键里的东西排序

若是年龄降序排序就是  o.age-this.age 

记住弄完接口直接放上面按上alt+Enter就可以完成重写 

public class Student implements Comparable<Student>{
 @Override
    // this  o
    public int compareTo(Student o) {
        //年龄升序排序
        return this.age-o.age;
    }
}

 解决方法二

TreeMap有一个有参构造器,支持创建Comparable比较器对象,以方便用来指定比较规则

下面进行的是身高降序排序 (将不会去比较年龄大小)

Map<Student ,String> map =new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o2.getHeight(),o1.getHeight());
            }
        });

使用lambda表达式简化代码 

  Map<Student ,String> map =new TreeMap<>( (o1,  o2) ->Double.compare(o2.getHeight(),o1.getHeight()));

其中当你使用该方法在有参数构造器时制定了比较规则,即使再学生类中重写,

但是会优先去执行有参数比较器的规则 

集合的嵌套

定义:集合中的元素又是一个集合 

 b514db3948a6456bb2bf7f47372a7e9f.png

 Map<String, List<String>> map= new HashMap<>(); 

//1.定义一个Map集合存储全部省份信息,和其对应的城市信息
        Map<String, List<String>> map= new HashMap<>();
        List<String> cities1 =new ArrayList<>();
        Collections.addAll(cities1,"苏州市","无锡市","常州市","镇江市","扬州市","泰州市");
        map.put("江苏省",cities1);
        System.out.println(map);

遍历值

 List<String> list = map.get("江苏省");
        for (String s : list) {
            System.out.println(s);
        } 

苏州市
无锡市
常州市
镇江市
扬州市
泰州市 

  map.forEach((p,c) ->
            {
            System.out.println(c);
        }); 

[苏州市, 无锡市, 常州市, 镇江市, 扬州市, 泰州市] 

  map.forEach((p,c)->
        {
            System.out.println(p+"->"+c);
        });
 

结果 

江苏省->[苏州市, 无锡市, 常州市, 镇江市, 扬州市, 泰州市] 

思考与总结

Collection<String> c =new ArrayList<>();

ArrayList<String> c1 =new ArrayList<>();

这两段代码有什么区别

 Collection<String> c = new ArrayList<>();

解释:

  • 接口 vs 实现:这里 c 是一个 Collection<String> 类型的变量,而 ArrayList<String> 是 Collection 接口的一个实现类。ArrayList 实现了 Collection 接口,因此可以将 ArrayList<String> 对象赋值给 Collection<String> 类型的变量。
  • 优点
    • 编程接口:使用 Collection<String> 类型可以让你的代码更加灵活。你可以轻松地更改 c 的实现类而不影响使用它的代码,例如改为 LinkedList 或其他 Collection 的实现,只要这些实现类符合 Collection 接口。
    • 抽象化:这种写法提供了一层抽象,有助于遵循面向接口编程的原则,提高代码的可维护性和扩展性。

2. ArrayList<String> c1 = new ArrayList<>();

解释:

  • 具体实现:这里 c1 是一个 ArrayList<String> 类型的变量,这直接表示你正在使用 ArrayList 类。ArrayList 是 Collection 接口的一个实现。
  • 优点
    • 明确实现:这种写法明确指定了使用 ArrayList 作为集合的具体实现。如果你知道自己总是需要 ArrayList 的特性,比如动态数组的特性和随机访问能力,直接使用 ArrayList 是合适的。
    • 直接访问实现特有方法:如果你需要使用 ArrayList 特有的方法(例如 ensureCapacity 或 trimToSize),你可以直接调用这些方法,而不需要先将 c1 强制转换为 ArrayList 类型。

总结

  • 使用 Collection<String>:提供了更高的抽象层次,使得代码更具灵活性和扩展性。你可以轻松地改变集合的具体实现而不需要修改代码的其他部分。
  • 使用 ArrayList<String>:明确地指定了集合的实现,可能在一些情况下会有特定的实现相关的优势,比如使用实现类的特定方法。

在实际编程中,推荐使用 Collection 类型来定义变量和方法的参数,这样可以使代码更具通用性和可维护性。具体实现类则可以在实际需要时使用。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值