Java-集合(6)

集合的选型

在开发中使用什么集合实现类,取决于业务的特点,然后进行选型。
首先需要判断存储的数据是单列的还是双列的

  • 单列的:Collection接口
  1. 允许重复:List接口
    一增删多:LinkedList[底层维护了一个双向链表]
    一改查多:ArrayList[底层维护了Object类型的可变数组]
  2. 不允许重复:Set接口
    一无序:HashSet[底层是HashMap,维护了一个哈希表(数组+链表+红黑树)]
    一有序:TreeSet
    一插入和取出顺序一致:LinkedHashSet[底层维护了数组+双向链表]
  • 双列的:Map接口
    1.键无序:HashMap[底层是哈希表(数组+链表+红黑树)]
    2.键排序:TreeMap
    3.键插入和取出的顺序一致:LinkedHashMap
    4.读取文件Properties

TreeSet

TreeSet也是实现了Set接口的一个实现类,他的主要特点是排序。
TreeSet集合底层实际上是一个TreeMap,而TreeMap集合底层是一个二叉树,也将TreeSet集合中的元素称为可排序组合
下面重点分析,是怎么实现排序的。

重点操作 使用有参构造器Comparator 的compare 方法,写一个匿名内部类作为形参在构造器
具体的排序方法由compare 自己定义
举例说明:String类型的排序

  1. 使用Comparator 匿名内部类作为传参写在构造器的形参列表,具体对比方法自己写
  2. 例如要使用String类型的长度作为排序就先向下转型为String,然后o1.length-02length
  3. 这样的话当使用add方法添加时,底层会调用匿名内部类Comparator的compare 方法,根据return的结果调整位置(底层是二叉树,所以调整的是树左右连接的位置)
  4. 当返回结果为大于0时,会调整集合数据的位置
  5. 当结果相等时就不添加了
public class TreeSet_ {
    public static void main(String[] args) {
        TreeSet treeSet =new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();
            }
        });
        treeSet.add("123");
        treeSet.add("12");
        treeSet.add("1");
        System.out.println(treeSet);
    }
}

排序结果:
[1, 12, 123]

在这里插入图片描述

TreeMap

TreeMap是Map的实现类,基本用法和上面的TreeSet差不多
有一点需要注意,当排序对比return相等时,key和TreeSet一样不会替换,但是value会替换,因为TreeSet是单列集合所以不重要,但是TreeMap是双列集合,需要注意一下这点

Collections工具类

Collections类是一个操作Set,List,Map等集合的工具类
比如对集合进行排序,查询,修改等等…
Collections种提供了一系列的静态的方法来帮助开发这实现对集合的操作

  • 排序方法
  1. reverse(List):反转List中的元素顺序
  2. shuffle(List):对List集合元素进行随机排序
  3. sort(List):根据元素的自然顺序对指定的LiST集合元素按照升序排序
  4. sort(List,Comparator):根据指定的Comparator比较器产生的顺序对List集合元素进行排序
  5. swap(List,int i,int j):将指定List集合中的i元素和j处元素进行交换

使用演示:

public class test2 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("tim");
        list.add("mary");
        list.add("jack");
        list.add("mile");
//        1. reverse(List):反转List中的元素顺序
        Collections.reverse(list);
        System.out.println(list);
//        2. shuffle(List):对List集合元素进行随机排序
        for (int i = 0; i < 5; i++) {
            Collections.shuffle(list);
            System.out.println(list);
        }
//        3. sort(List):根据元素的自然顺序对指定的LiST集合元素按照升序排序
        Collections.sort(list);
        System.out.println(list);
//        4.  sort(List,Comparator):根据指定的Comparator比较器产生的顺序对List集合元素进行排序
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();//按照长度排序
            }
        });
        System.out.println(list);
//        5. swap(List,int i,int j):将指定List集合中的i元素和j处元素进行交换
        Collections.swap(list,0,3);
        System.out.println(list);
    }
}

输出结果:
[mile, jack, mary, tim]
[jack, mary, mile, tim]
[tim, mary, jack, mile]
[mary, tim, jack, mile]
[mary, mile, jack, tim]
[mary, jack, tim, mile]
[jack, mary, mile, tim]
[tim, jack, mary, mile]
[mile, jack, mary, tim]

  • 查找替换
  1. max(Collection):根据元素的自然顺序返回集合中最大的元素
  2. max(Collection,Comparator):根据Comparator比较器的结果返回集合中最大的元素
  3. min(Collection):返回集合中最小的元素
  4. min(Collection,Comparator):根据Comparator比较器的结果返回集合中最小的元素
  5. frequency(Collection,Object):返回集合中Object出现的次数
  6. copy(List dest,List src):将src的数据复制到dest中
  7. replaceAll(List list,Object oldVal,Object newVal):将list集合中的oldval替换成newval

使用演示

public class test2 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("tim");
        list.add("mary");
        list.add("jack");
        list.add("mile");
        list.add("mile");
//        1. max(Collection):根据元素的自然顺序返回集合中最大的元素
        System.out.println(Collections.max(list));
//        2. max(Collection,Comparator):根据Comparator比较器的结果返回集合中最大的元素
        System.out.println(Collections.max(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();
            }
        }));
//        3. min(Collection):返回集合中最小的元素
        System.out.println(Collections.min(list));
//        4. min(Collection,Comparator):根据Comparator比较器的结果返回集合中最小的元素
        System.out.println(Collections.min(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();
            }
        }));
//        5. frequency(Collection,Object):返回集合中Object出现的次数
        System.out.println(Collections.frequency(list,"mile"));
//        6. copy(List dest,List src):将src的数据复制到dest中
        ArrayList list2 = new ArrayList();
        for (int i = 0; i < list.size(); i++) {//先给新集合开一样大的空间,否则会报错
            list2.add("");
        }
        Collections.copy(list2,list);
        System.out.println(list2);
//        7. replaceAll(List list,Object oldVal,Object newVal):将list集合中的oldval替换成newval
        Collections.replaceAll(list,"mile","lll");
        System.out.println(list);

    }
}

输出结果:
tim
mary
jack
tim
2
[tim, mary, jack, mile, mile]
[tim, mary, jack, lll, lll]

集合练习

  1. 编写实现下面要求的程序
    1):封装一个新闻类,包含标题和内容属性,提供get,set方法,重写toString方法,打印对象时只打印标题
    2):只提供一个戴参数的构造器,且实例化对象时只初始化标题,且实例化两个对象
    新闻标题1:新冠确诊病例超千万,数百万印度角度赴恒河“圣浴”引民众担忧
    新闻标题2:男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生
    3):将新闻对象添加到ArrayList集合中,且进行倒序遍历
    4)在遍历集合的过程中,对新闻标题进行处理,超过15个字的只保留前15个,然后再后边加上“…”
    5)再控制台打印遍历出经过处理的新闻标题。
public class HomeWork3 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(new News("新冠确诊病例超千万,数百万印度角度赴恒河“圣浴”引民众担忧"));
        list.add(new News("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生"));
        for (int i = list.size()-1; i >=0; i--) {//倒叙打印
            News news = (News) list.get(i);
            System.out.println(protitle(news.title));;
        }

    }
    public static String protitle(String itile){
        if (itile == null){
            return null;
        }
        if (itile.length()>15){
            return itile.substring(0,15)+"...";
        }
        return itile;
    }
}
class News{
    String title;
    String content;
    public News(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "News{" +
                "title='" + title + '\'' +
                '}';
    }
}

运行结果:
男子突然想起2个月前钓的鱼还在…
新冠确诊病例超千万,数百万印度…

  1. 使用ArrayList完成对 对象Car{name,price}的各种操作
    1).add:添加单个元素
    2):remove:删除指定元素
    3):contains:查找元素是否存在
    4):size:获取元素个数
    5):isEmpty:判断是否为空
    6):clear:清空
    7):addAll:添加多个元素
    8);containsAll:查找多个元素是否都存在
    9);removeAll:删除多个元素
    使用增强for和迭代器来遍历所有car,需要重写Car的toString方法
/*
 *@author WINorYU
 */
public class HomeWork5 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
//        1).add:添加单个元素
        list.add(new Car("宝马",250000));
        list.add(new Car("宾利",5500000));
        Car c = new Car("BJ40",180000);
        list.add(c);
//        2):remove:删除指定元素
        list.remove(1);
        System.out.println(list);
//        3):contains:查找元素是否存在
        System.out.println(list.contains(c));
//        4):size:获取元素个数
        System.out.println(list.size());
//        5):isEmpty:判断是否为空
        System.out.println(list.isEmpty());
//        6):clear:清空
        list.clear();
        System.out.println(list);
//        7):addAll:添加多个元素
        ArrayList list2 = new ArrayList();
        list2.add(c);
        list2.add(new Car("宾利",5500000));
        list.addAll(list2);
//        8);containsAll:查找多个元素是否都存在
        System.out.println(list.containsAll(list2));
//        9);removeAll:删除多个元素
        list.removeAll(list2);
        System.out.println(list);
//        使用增强for和迭代器来遍历所有car,需要重写Car的toString方法
        //先加几个进去
        list.add(new Car("宝马",250000));
        list.add(new Car("宾利",5500000));
        list.add(c);
        for (Object o1:list) {
            System.out.println(o1);
        }
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
        }
    }
}
class Car{
    String name;
    double price;

    public Car(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
  1. 按要求完成下列任务
    1)使用HashMap类实例化一个Map类型的对象m,键和值分别用于存储员工的姓名和工资,存入数据如下 jack-650元,tom-1200元,smith-2900元
    2)将jack的工资改为2600元
    3)为所有员工的工资加100元
    4)遍历集合中所有的员工和工资
public class HomeWork6 {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("jack",650);
        map.put("tom",1200);
        map.put("smith",2900);
        //修改jack的工资
        map.put("jack",2600);
        //为所有的员工工资+100,遍历
        Set EntrySet =map.entrySet();
        for (Object node:EntrySet) {
            Map.Entry entry = (Map.Entry)node;
            map.put(entry.getKey(),(Integer)entry.getValue()+100);
            System.out.println(entry.getKey()+"-"+entry.getValue());
        }
    }

}
  1. 简答题
    分析HashSet和TreeSet的去重机制是什么

HashSet的去重机制:hashCode() + equals(),底层先通过将要存入的对象进行运算,得到一个hash值,通过hash值得到要存入的索引位置,如果发现table索引所在的位置没有元素,则直接放入,如果有已经有元素了,则通过equals进行比较{遍历比较},比较后如果不同就加入在后面,相同就不加入

TreeSet的去重机制:如果传入了一个Comparator匿名对象,则以实现的compare去重,如果返回的结果是0则认为是相同的元素,就不添加。反之就添加,如果没有传入Comparator匿名对象,则以将要添加的对象类型实现的Compareable接口的compareTo方法进行去重

  1. 查看下列代码分析是否有错误,如果有,说明为什么
public class test9{
    public static void main(String [] args){
        TreeSet treeset = new TreeSet();
        treeset.add(new Person());
    }
}
class Person{}

会报类型转换异常,ClassCastException,因为实例化TreeSet时没有传入Comparator匿名对象,所以当添加对象时,会自动去调用要添加的对象的compareTo方法,而Person类并没有实现Compareable接口,在底层源码中TreeSet会先将要添加对象向上转型成Compareable,但是Person和Compareable之间没有关系,所以会类型转换异常

  1. 分析下列代码会输出什么
    //已知,Person类按照id和name重写了hashCode方法
@SuppressWarnings({"ALL"})
public class test9{
    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";//将p1的那么改成了“CC”
        hashSet.remove(p1);//这里因为remove是根据hash索引来删除的,第一次添加p1是1001-AA,而上面把p1的AA改成了CC,
        // 所以hash值不一样了,所以最终找到的索引位置也不一样,从而导致删除失败
        System.out.println(hashSet);//因为删除失败所以,还是有两个1001-CC和1002-BB
        hashSet.add(new Person(1001,"CC"));//这里还是跟删除一样的道理,根据hash值计算得到索引,因为p1的索引是1001-AA得到的
        //虽然后面改成了CC,但是索引位置是没有改的。前面又只是删除1001-CC计算的索引,并没有添加,所以索引自然不会又重复的,最终可以添加成功
        System.out.println(hashSet);//输出三个元素
        hashSet.add(new Person(1001,"AA"));//这里又添加了一个跟原始p1一样的id和name,所以计算得到的索引会和现在的p1:1001-CC是相同的索引
        //但是呢因为现在的p1那么不是AA了而是CC,所以会添加在p1的后面,最终添加成功
        System.out.println(hashSet);//输出4个元素
    }
}
class Person{
    int id;
    String name;

    public Person(int id, String name) {
        this.id = id;
        this.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);
    }
}
  1. 写出ArrayList和Vector的区别
实现类底层结构版本线程安全和效率扩容机制
ArrayList可变数组jdk1.2不安全,效率高有参构造器按照1.5倍扩容/无参构造器初始10,后面都是1.5倍
Vector可变数组jdk1.0安全,效率不高有参构造初始按照2倍扩容/无参构造器初始10,后面都是2倍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值