Java-Day-20( Collections 工具类 + 集合练习 )

Java-Day-20

Collections 工具类

介绍

  • Collections 是一个操作 Set、List 和 Map 等集合的工具类 ( 仅有无参 )
  • Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作

常用方法

排序操作 ( 均为 static 方法 )

  • reverse(List):反转 List 中的元素顺序
  • shuffle(List):对 List 集合元素进行随机排序
  • sort(List):根据元素的自然顺序 ( 字符串 ) 对指定 List 集合元素按升序排序
  • sort(List, Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
  • swap(List, int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
public static void main(String[] args) {
    List list = new ArrayList();
    list.add("zyz");
    list.add("java");
    list.add("duang");

    //        反转
    Collections.reverse(list);
    System.out.println("list = " + list);
    //        随机
    Collections.shuffle(list);
    //        字符串
    Collections.sort(list);
    //        指定
    Collections.sort(list, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            //                可选择性加入 instanceof String 安全校验
            //                按字符串长度大小
            return ((String) o1).length() - ((String) o2).length();
        }
    });
    System.out.println("list = " + list);
    //        指定交换
    Collections.swap(list, 0, 1);
    System.out.println("交换后的 list = " + list);

查找、替换

public static void main(String[] args) {
    List list = new ArrayList();
    list.add("zyz");
    list.add("java");
    list.add("duang");
    list.add("java");

    //        Object max(Collection)
    System.out.println("返回自然顺序最大元素=" + Collections.max(list));

    //        Object max(Collection, Comparator)
    Object maxObject = Collections.max(list, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            //                返回长度最大元素
            return ((String) o1).length() - ((String) o2).length();
        }
    });
    System.out.println("返回长度最大元素=" + maxObject);
    //        int frequency(Collection, Object)
    System.out.println("java出现的次数=" + Collections.frequency(list, "java"));

    //        void copy(List dest, List src):将 src 内容复制到 dest 中
    ArrayList dest = new ArrayList<>();
    //        因为空间大小比较的是size,所以要给dest以size大小
    //        注意:length 和 size 不同
    for (int i = 0; i < list.size(); i++) {
        dest.add("");
    }

    Collections.copy(dest, list);
    //        若是拷贝空间不够存就会抛异常报错
    System.out.println("拷贝list后的dest=" + dest);
    //        替换 java 为 zyzjava
    Collections.replaceAll(list, "java", "zyzjava");
    System.out.println("替换操作后的list=" + list);
}

集合作业练习

一、

  1. 封装一个新闻类,包含标题和内容属性,提供 get、set 方法,重写 toString 方法,打印对象时只打印标题
  2. 只提供一个带参数的构造器,实例化对象时,只初始化标题,并实例化两个对象:新闻一标题:新冠确诊病例超千万,数百万印度教信徒赴恒河“圣浴”引民众担忧;新闻二标题:男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生
  3. 将新闻对象添加到 ArrayList 集合中,并且进行倒序遍历
  4. 在遍历集合过程中,对新闻标题进行处理,超过 15 字的只保留前 15 个,后面就加 " … ”
  5. 在控制台打印遍历出经过处理的新闻标题
public class test1 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new News("新冠确诊病例超千万,数百万印度教信徒赴恒河\"圣浴\"引民众担忧")); // 注意转义字符
        arrayList.add(new News("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生"));

        int size = arrayList.size();
        for (int i = size - 1; i >= 0; i--) {
//            System.out.println(arrayList.get(i));
            News news = (News) arrayList.get(i);
            System.out.println(processTitle(news.getTitle()));
        }
    }
//    写一个方法处理标题
    public static String processTitle(String title) {
        if (title == null) {
            return "";
        } else if (title.length() > 15) {
            return title.substring(0, 15) + " ... "; // 前闭后开
        } else {
            return title;
        }
    }


}

class News {
    private String title;
    private String content;

    public News(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }
//    此处为简洁省略了全部的set和get方法
    @Override
    public String toString() {
        return "News{" +
                "title='" + title + '\'' +
                '}';
    }
}

二、

使用 ArrayList 完成对对象 Car { name, price } 的各种操作

Car car = new Car("宝马", 400000);

Car car2= new Car("宾利",5000000);

  1. add:添加单个元素
  2. remove:删除指定元素 ( 元素对象 )
  3. contains:查找元素是否存在
  4. size:获取元素个数
  5. isEmpty:判断是否为空
  6. clear:清空
  7. addAll:添加多个元素
  8. containsAll:查找多个元素是否都存在
  9. removeAll:删除多个元素 ( 接口实现类型 )

使用增强for和迭代器来遍历所有的car

public class test2 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        Car car = new Car("宝马", 400000);
        Car car2= new Car("宾利",5000000);
        Car car3= new Car("别克",80000);
        arrayList.add(car);
        arrayList.add(car2);
        arrayList.add(car3);
        arrayList.remove(0); // 删除索引:0 (第一个位置)处对象
        arrayList.remove(car2); // 也可以指定删除某对象
        System.out.println(arrayList.size()); // 1
        System.out.println(arrayList.isEmpty()); // F
//        arrayList.clear(); // 清空
        arrayList.addAll(arrayList); // 集合可以自己放自己
        System.out.println(arrayList.containsAll(arrayList)); // T 查找多个元素是否存在,放的是Collection接口实现类
//        arrayList.removeAll(arrayList); // 删除多个元素,放的是 Collection接口实现类
        System.out.println(arrayList);
        for (Object o : arrayList) {
            System.out.println(o);
        }

        Iterator iterator = arrayList.iterator(); // 勿忘前提获取
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }
    }
}

class Car {
    private String name;
    private double price;

    public Car(String name, double price) {
        this.name = name;
        this.price = price;
    }
//   set、get 方法。。。
    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

三、

  1. 使用 HashMap 类实例化一个 Map 类型的对象 m,键 ( String ) 和值 ( int ) 分别用于存储员工的姓名和工资,存入数据如下: jack-650 元;tom-1200 元;smith-—--2900 元;
  2. 将 jack 的工资更改为 2600元
  3. 为所有员工工资加薪 100 元
  4. 遍历集合中所有的工资
public class test3 {
    public static void main(String[] args) {
        Map m = new HashMap();
        m.put("jack", 650); // 有自动装箱:int — Integer
        m.put("tom", 1200);
        m.put("smith", 2900);
        System.out.println(m);

//        更新就可以理解为替换,直接输入同k不同v
        m.put("jack", 2600);

//        F1:T
//        利用keySet得到每个键,然后循环改值
        Set keySet = m.keySet();
        for (Object key : keySet) {
//            利用put的替换机制完成更新
            m.put(key, (Integer)m.get(key) + 100);
        }

//        F2:F?
//        只获取每个值并不能对每个值进行根本上的修改,因为keySet、values本是为了方便遍历查看,修改还得是put替换
//        Collection values = m.values();
//        for (Object o : collection) {
//            o = (Integer) o + 100;
//            System.out.println(o);
////            只是循环显示的改了,实际上原数并无变化
//        }

//        F3:T
//        或者是用entrySet直接拿到所有
//        Set entrySet = m.entrySet();
//        Iterator iterator = entrySet.iterator();
//        while (iterator.hasNext()) {
//            Map.Entry entry = (Map.Entry)iterator.next();
//            entry.setValue((Integer)entry.getValue() + 100);
//        }

        Collection values = m.values();
        for (Object value : values) {
            System.out.println("遍历所有工资 = " + value);
        }

        System.out.println(m);
    }
}

四、

HashSet 和 TreeSet 去重机制的

  • HashSet:hashCode() + equals(),底层运算得 hash 值来找索引处存放,若是有数据的话就进行 equals 遍历比较 ( 默认看字符串,最好由程序员来决定 ),比较后不相同就加入

  • TreeSet:传入 Comparator 匿名对象,就实现 compare 去重,返回 0 就表示重复不添加;没传入 Comparator 的话就以添加的对象 ( 常见 String ) 实现的 Comparable 接口内的 compareTo 完成去重

五、

分析下面代码是否会抛出异常

// main:
TreeSet treeSet = new TreeSet();
treeSet.add(new Person());

// 类中无任何操作
class Person { }
  • 会抛出异常:ClassCastException

  • 因为无参的话会调用 compare():return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2) : comparator.compare((K)k1, (K)k2);,而 (Comparable<? super K>)k1 中 k1 即 Person 类无法上转成 Comparable 接口,更无 compareTo(),则抛异常

  • 解决方法之一为改写 Person:( 即便返回 0 也只会导致只能添加一个而不会再报错 )

    class Person implements Comparator {
        @Override
        public int compare(Object o1, Object o2) {
            return 0;
        }
    }
    

六、

查看代码输出:( 已知 Person 类按照 id 和 name 重写了 hashCode 和 equals 方法 )

public class test6 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        Person p1 = new Person(1001, "AA");
        Person p2 = new Person(1002, "BB");
        hashSet.add(p1);
        hashSet.add(p2);
        p1.name = "CC";
        hashSet.remove(p1); // 1.
        System.out.println(hashSet);
        hashSet.add(new Person(1001, "CC")); // 2.
        System.out.println(hashSet);
        hashSet.add(new Person(1001, "AA")); // 3.
        System.out.println(hashSet);
    }
}

class Person {
    private int id;
    public String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}
  • 输出为:

    • [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]
    • [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}]
    • [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
  • 分析:

    • 重写前:hash = 1020382489
    • 重写后:hash = 34072
      • 重写了 hashCode 方法,所以 map.put 后 hash() 计算操作 ( 根据 key.hashCode() )
      • key.hashCode() 调用的就是 Person 里重写的方法
      • 重写方法里返回 Object.hash 又是返回 Arrays.hashCode ...... 等完成哈希值的计算
      • 这样就是根据对象的 " 属性值 " 计算哈希值,和对象地址就无关了
    1. 处因为重写,所以 remove 删的是 (1001, "AA") 索引处的值,(1001, "AA") 索引处还是存着 (1001, "CC")
    2. add 是把 (1001, "CC") 正确得放进了其索引处 ( 此时两个 CC,一个是因为更改值,一个是正确索引存储 )
    3. add 存放 (1001, "AA") 索引查找时有 CC 占位了,但两者 hash 不同所以 (1001, "AA") 直接放在了链尾
  • 不重写 hashCode 和 equals 方法的话 ( 或只重写 equals 的话 ),输出为:

    • [Person{id=1002, name='BB'}]
      • 同地址,哈希值相同 remove 照样删
    • [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]
    • [Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
posted @ 2023-05-12 16:41  朱呀朱~  阅读(13)  评论(0编辑  收藏  举报