首页 > 编程语言 >Java小白一文讲清Java中集合相关的知识点(九)

Java小白一文讲清Java中集合相关的知识点(九)

时间:2024-09-12 14:50:18浏览次数:3  
标签:知识点 p1 Java name 讲清 person set println new

Map和Set常用的API

Map 常用API

  • put(K key, V value): 将指定的键值对插入到映射中。
  • get(Object key): 返回与指定键关联的值,如果键不存在则返回 null
  • remove(Object key): 移除指定键及其对应的值。
  • containsKey(Object key): 判断是否包含指定的键。
  • containsValue(Object value): 判断是否包含指定的值。
  • keySet(): 返回映射中所有键的 Set 视图。
  • values(): 返回映射中所有值的 Collection 视图。
  • entrySet(): 返回映射中所有键值对的 Set 视图。
  • size(): 返回映射中键值对的数量。
  • clear(): 清空映射中的所有键值对。
  • isEmpty(): 判断映射是否为空。

Set 常用API

  • add(E e): 向集合中添加指定元素,如果元素已存在则不会重复添加。
  • remove(Object o): 移除集合中的指定元素。
  • contains(Object o): 判断集合中是否包含指定元素。
  • size(): 返回集合中元素的数量。
  • isEmpty(): 判断集合是否为空。
  • clear(): 清空集合中的所有元素。
  • iterator(): 返回集合中元素的迭代器。
  • addAll(Collection<? extends E> c): 将指定集合中的所有元素添加到此集合

练习

在这里插入图片描述

import java.util.*;

@SuppressWarnings({"all"})
public class Journey {
    public static void main(String[] args) {
        News news1 = new News("新冠确诊病例超千万,数百万印度信徒前往恒河\"圣浴\"引发民众担忧");
        News news2 = new News("男子突然想起2个月前钓的鱼还在网兜中,捞起一看赶紧放生");
        ArrayList list = new ArrayList();
        list.add(news1);
        list.add(news2);
        //直接reverse可以的,但别忘了这样会直接改变list的内部结构
        //有些情况下需要注意这一点,要求不改变list的内部结构时,可以for循环遍历
        //当然,你也可以下面这样反转然后让一个对象来接收

//        Collections.reverse(list);

        int size = list.size();
        for (int i = size-1; i >= 0; i--) {
            News news = (News)list.get(i);
            System.out.println(processTitle(news.getTitle()));

        }



    }
    //专门写了个方法,处理现实新闻标题  process处理
    public static String processTitle(String title){
        if(title==null){
            return "";
        }
        if(title.length()>15){
            //别忘了是左闭右开哈
            return title.substring(0,15)+"...";//[0,15)
        }else{
            return title;
        }

    }
}
class News{
    private String title;
    private String desc;

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

    @Override
    public String toString() {
        //只打印标题
        return  title ;
    }

    public String getTitle() {
        return title;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
//输出如下:
男子突然想起2个月前钓的鱼还在...
新冠确诊病例超千万,数百万印度...

在这里插入图片描述

public static void main(String[] args) {
        ArrayList list = new ArrayList();
        //添加
        Car BMW = new Car("宝马", 400000);
        Car Binli = new Car("宾利", 5000000);
        list.add(BMW);
        list.add(Binli);
        System.out.println(list);
        //[Car{name='宝马', price=400000.0}, Car{name='宾利', price=5000000.0}]

        boolean b = list.contains(Binli);
        System.out.println(b);//true

        //获取元素个数
        int size = list.size();
        System.out.println(size);//2

        //判断是否为空
        System.out.println(list.isEmpty());//false

        //clear  清空
//        list.clear();
        System.out.println(list.isEmpty());//true


        ArrayList testlist = new ArrayList();
        testlist.add(true);
        testlist.add(1110);
        list.addAll(0,testlist);
        System.out.println(list);
        //[true, 1110, Car{name='宝马', price=400000.0}, Car{name='宾利', price=5000000.0}]

        //删除多个元素
        list.removeAll(testlist);
        System.out.println(list);
        //[Car{name='宝马', price=400000.0}, Car{name='宾利', price=5000000.0}]

        //迭代器
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
        /**
         * 重写toString之后输出结果:
         * 品牌名:宝马	price:400000.0
         * 品牌名:宾利	price:5000000.0
         */

        //增强for
        System.out.println("=====================增强for=================");
        for (Object o :list) {
            System.out.println(o);

        }
        /**
         * 品牌名:宝马	price:400000.0
         * 品牌名:宾利	price:5000000.0
         */

    }

在这里插入图片描述

    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        hashMap.put(new Employee("jack",650).getName(),new Employee("jack",650).getSal());
        hashMap.put(new Employee("tom",1200).getName(),new Employee("tom",1200).getSal());
        hashMap.put(new Employee("smith",2900).getName(),new Employee("smith",2900).getSal());


        System.out.println(hashMap);
        //{tom=1200.0, smith=2900.0, jack=650.0}

        //改jack的工资
        hashMap.put("jack",2600.0);
        System.out.println(hashMap);
        //{tom=1200.0, smith=2900.0, jack=2600}

        //给员工加薪资100---keySet实现
        Set keySet = hashMap.keySet();
        for (Object key :keySet) {
            //注意,下面这行,涨薪100就是更新value嘛,但是hashMap.get(key)
            //返回的是Object,所以要向下转型
            hashMap.put(key,(Double)hashMap.get(key)+100.0);
        }

        System.out.println(hashMap);
        //{tom=1300.0, smith=3000.0, jack=2700.0}

        //给员工再涨200---entrySet实现
        Set set = hashMap.entrySet();
        for (Object o :set) {
            Map.Entry entry = (Map.Entry)o;
            hashMap.put(entry.getKey(),(Double)entry.getValue()+200.0);
        }
        System.out.println(hashMap);
        //{tom=1500.0, smith=3200.0, jack=2900.0}


        //遍历集合中的所有员工
        Set emps = hashMap.keySet();
        System.out.println(emps);
        //[tom, smith, jack]

        //迭代器实现遍历
        Set set1 = hashMap.entrySet();
        Iterator iterator = set1.iterator();
        while (iterator.hasNext()) {
            Object obj =  iterator.next();
            Map.Entry entry = (Map.Entry)obj;
            System.out.println("员工姓名-"+entry.getKey()+"\t工资:"+entry.getValue());
        }
        //员工姓名-tom	工资:1500.0
        //员工姓名-smith	工资:3200.0
        //员工姓名-jack	工资:2900.0

        //遍历集合中的所有工资
        Collection values = hashMap.values();
        System.out.println(values);
        //[1500.0, 3200.0, 2900.0]

    }

在这里插入图片描述

HashSet的去重机制: HashCode() 和 equals() 相配合,底层先通过存入一个对象,进行运算得到一个hash值,然后通过hash值得到索引,如果发现table表的索引所在的位置,没有数据,就直接存放进去,如果有数据,就进行equals比较(遍历比较),这里的equals的具体比较是可以由程序员来重写的,我们可以按照我们想要的规则来判定是否相等;如果比较后,不相同,那么可以加入,反之,则无法加入
    
TreeSet的去重机制:如果你传入了一个Comparator匿名对象,就使用实现的compare方法来实现去重,如果方法返回0,就认为是相同的数据/元素,就不添加了,如果没有传入一个Comparator匿名对象,则以你添加的对象实现的Compareable接口的compareTo方法去重
    去重机制的核心——比较规则
TreeSet 的去重机制依赖于元素的比较规则,而比较规则有两种方式:

1.通过 Comparable 接口:如果元素类实现了 Comparable 接口,TreeSet 会调用元素的 compareTo() 方法来进行比较。例如:

        class Person implements Comparable<Person> {
            private String name;
            private int age;

            public int compareTo(Person other) {
                // 按名字比较
                return this.name.compareTo(other.name);
            }
        }
在这个例子中,当两个 Person 对象的 name 相同时,TreeSet 会认为它们是重复的,不会插入第二个元素。

2.通过 Comparator 接口:如果 TreeSet 构造时提供了一个 Comparator,则 TreeSet 会使用该 Comparator 的 compare() 方法来比较元素,而不是依赖于元素自身的 compareTo() 方法。例如:

        TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                // 按年龄比较
                return Integer.compare(p1.getAge(), p2.getAge());
            }
        });
通过这种方式,TreeSet 会根据年龄来去重,两个年龄相同的 Person 对象会被认为是相等的,不允许重复插入。
    
    
    TreeSet treeSet = new TreeSet();
	treeSet.add(new Person());	
	class Person{}

//代码分析题
        因为 TreeSet() 的构造器中没有传入 Comparator,所以它默认认为插入的元素需要实现 Comparable 接口。
        当你调用 treeSet.add(new Person()) 时,TreeSet 试图将 Person 对象转型为 Comparable。
        但由于 Person 没有实现 Comparable 接口,无法完成强制类型转换,导致抛出了 ClassCastException。
为什么会抛出异常?
	TreeSet 的工作原理是基于二叉树(通常是红黑树)来存储元素,因此它要求放入 TreeSet 的对象必须是 可比较的,
     也就是说,放入的对象需要实现 Comparable 接口或者在构造 TreeSet 时提供一个 Comparator。

	 然而,在上面的代码中,Person 类并没有实现 Comparable 接口,也没有提供 Comparator,
     所以当你尝试向 TreeSet 中添加一个 Person 对象时,TreeSet 无法确定如何比较这些 Person 对象。
     这时,在执行 add() 方法时,程序会抛出 ClassCastException 异常。

TreeSet 底层在插入元素时,会调用以下方法:
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
其中 m 是 TreeMap,TreeMap 通过 compareTo() 或 compare() 方法来比较元素。而在比较的时候,
 如果 Person 没有实现 Comparable 接口,那么 TreeSet 将无法进行元素的排序或比较,导致异常。

解决方案
要解决这个问题,必须确保 Person 类可以进行比较,通常有两种方法:
1.实现 Comparable 接口:

    class Person implements Comparable<Person> {
        @Override
        public int compareTo(Person o) {
            // 定义比较规则,例如按某个字段比较
            return 0;
        }
    }
2.提供一个 Comparator:
    TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
        @Override
        public int compare(Person o1, Person o2) {
            // 定义比较规则
            return 0;
        }
    });

在这里插入图片描述

@SuppressWarnings({"all"})
public class Journey {
    public static void main(String[] args) {
        HashSet set = new HashSet();
        person p1 = new person(1001, "AA");
        person p2 = new person(1002, "BB");
        set.add(p1);
        set.add(p2);
        System.out.println("只添加了p1、p2后的原始的set");
        System.out.println(set);
        p1.name = "CC";
        set.remove(p1);

        System.out.println("更改name,remove p1后,set为:");
        System.out.println(set);

        set.add(new person(1001,"CC"));
        System.out.println("第二次,尝试新添加了1001 CC 后的set 为:");
        System.out.println(set);

        set.add(new person(1001,"AA"));
        System.out.println("第三次,尝试新添加1001 AA后,此时的set为:");
        System.out.println(set);


    }
}
@SuppressWarnings({"all"})
class person{
    public int id;
    public 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);
    }
    @Override
    public String toString() {
        return "person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
//输出如下:
只添加了p1、p2后的原始的set
[person{id=1002, name='BB'}, person{id=1001, name='AA'}]
更改name,remove p1后,set为:
[person{id=1002, name='BB'}, person{id=1001, name='CC'}]
第二次,尝试新添加了1001 CC 后的set 为:
[person{id=1002, name='BB'}, person{id=1001, name='CC'}, person{id=1001, name='CC'}]
第三次,尝试新添加1001 AA后,此时的set为:
[person{id=1002, name='BB'}, person{id=1001, name='CC'}, person{id=1001, name='CC'}, person{id=1001, name='AA'}]

//第一次修改后,输出的是两个Person对象
     1. 更改 p1.name 后调用 set.remove(p1):
    代码中,p1.name 被修改为 "CC" 后,set.remove(p1) 被调用。为了理解为什么这个操作没有成功移除元素,
    我们需要回顾一下 HashSet 的工作原理:

       HashSet 是基于 哈希表 的数据结构,它依赖于元素的 hashCode() 和 equals() 方法来确定是否存在某个元素。
      当你调用 set.remove(p1) 时,HashSet 会通过 p1 的 hashCode() 找到相应的桶位置。然而,
      此时 p1 的 name 属性已经从 "AA" 改成了 "CC",因此 p1 的 hashCode() 已经发生了改变,与最初插入的 p1 不同了。
      因为 HashSet 依赖 hashCode() 来确定元素位置,而修改 name 后的 p1 的 hashCode() 不再匹配原始存储位置,
      remove(p1) 找不到正确的位置,导致无法成功删除 p1。
    
    因此,在第一次 remove(p1) 后,p1 并没有被删除,set 中的元素是:
    [person{id=1002, name='BB'}, person{id=1001, name='CC'}]    
//第二次修改新增后,输出的是三个person对象
    2.添加 new person(1001, "CC")
    HashSet 的工作原理
	  HashSet 基于 哈希表 实现,它通过两个方法来维护元素的唯一性:
		hashCode():用于计算对象的哈希值(确定对象存储的桶位置)。
		equals():用于判断两个对象是否相等。
	  在 HashSet 中,添加一个元素时,流程如下:
            1.根据元素的 hashCode() 确定存储的桶位置。
            2.在该位置上,用 equals() 检查是否已经存在相同的元素。
                2.1如果 equals() 返回 true,认为是重复元素,不会添加。
                2.2如果 equals() 返回 false,认为是不同元素,允许添加。
    当你修改 p1.name = "CC" 后,p1 的 hashCode() 变了。因为 hashCode() 是根据 id 和 name 来计算的,
    现在 p1 的 name 变成了 "CC",所以新的哈希值不同于最初插入时的值。
	然而,HashSet 并不会去重新计算存储在它内部对象的哈希值,也就是说,虽然对象的属性变了,
    但是它在 HashSet 中的存储位置仍然是基于原来的哈希值。
    第一次 remove(p1) 失败:

    当你尝试执行 set.remove(p1) 时,HashSet 会根据 p1 当前的 hashCode() 去查找它的存储位置。
    但是,p1 的 hashCode() 已经变了,HashSet 会去错误的桶位置查找,而不是最初插入的桶位置。
    由于在这个错误的桶位置上没有找到 p1,remove() 操作失败,p1 没有被删除。
    修改了 p1.name 之后,p1 的哈希值发生了变化,但 HashSet 没有重新计算和更新该对象在集合中的位置。
    因此,后续插入 new person(1001, "CC") 时,HashSet 认为它是一个新元素,导致集合中出现了两个 "CC"。
//第三次修改后,输出的是四个person对象
    添加了一个新的 person(1001, "AA"),这个对象与 set 中的任何现有元素都不相等,
    新的 person 对象,id 为 1001,name 为 "AA"。
	这个新对象的 hashCode() 是基于 id = 1001 和 name = "AA" 计算出来的
    当 HashSet 插入一个元素时,首先根据元素的 hashCode() 决定放入哪个哈希桶(存储位置)。
	然后,它会在该位置上通过调用 equals() 方法来比较新元素和已有的元素,看看是否有重复的元素。
    因为它的 name 为 "AA" 而不是 "CC",并且 equals() 和 hashCode() 都不同于现有的元素。
    于是,这个对象被成功添加到 set 中;

说下ArrayList和Vector的各自的不同之处

底层结构线程安全?效率?扩容机制
ArrayList可变数组不安全,效率高如果使用有参构造器,按照1.5倍扩容,
如果是无参构造器,第一次扩容到10,
第二次之后开始按照1.5倍扩容
Vector可变数组Object[ ]安全,效率不高如果是无参,默认是10,满了之后,按照2倍扩容,
如果是指定大小创建Vector,则每次按照2倍扩容

标签:知识点,p1,Java,name,讲清,person,set,println,new
From: https://blog.csdn.net/Kerwin_D/article/details/142174191

相关文章

  • C++知识点:size_t, a.at(i), reverse函数
    1.size_t`size_t`是一种在C/C++编程中非常常用的数据类型,它定义在`<stddef.h>`或者`<cstdlib>`等头文件中,通常用来表示**大小**或**长度**。###关键特性:1.**无符号类型**:`size_t`是无符号整数类型,表示它只能存储非负整数。因此,它不会用于存储负值,这使得它非常适合表示诸如......
  • JAVA面试官问你:CPU狂飙900%,该怎么处理?【转】
    首先,说明一下问题:CPU飙升200%以上是生产容易发生的场景场景:1:MySQL进程飙升900%大家在使用MySQL过程,想必都有遇到过CPU突然过高,或者达到200%以上的情况。数据库执行查询或数据修改操作时,系统需要消耗大量的CPU资源维护从存储系统、内存数据中的一致性。并发量大并且大量SQL性能低......
  • 基于java+SpringBoot+Vue的小徐影城管理系统设计与实现
    开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis工具:IDEA/Ecilpse、Navicat、Maven系统简介小徐影城管理系统是一款基于Java、SpringBoot和Vue.js技术开发的影院管理系统,旨在为用户提供一个便捷、高效的在线购票和影院管理平台。系统通过B/S架构,实现了管理员和用......
  • 【java逆向】3分钟理清Java对象头里面的那些杂事
    原创龙虾编程对象头是一个对象用于保存自身状态的区域,在HotSpot虚拟机中,对象在堆内存中存储的布局可以划分为三个部分:对象头(Header)、实例数据(InstanceData)、对齐填充(Padding),如下如所示:在Java中普通对象和数组对象的对象在布局上存在一定的差异,数组对象相比普通对象多了数......
  • 全国增值税发票查验接口平台-JavaScript发票验真api示例
    全国增值税发票查验接口平台旨在优化纳税服务,加强企业发票管理,确保税收工作的准确性。企业财务可以通过发票查验接口方便快捷的验证增值税发票管理系统开具发票的真伪,以实现发票的自动化管理,减少人工操作失误,提高识别、录入、查验的准确性和工作效率,从而有效防止税务欺诈和逃......
  • Docker脚本一键打包java镜像运行备份多端口共存
    效果./docker_build.sh8081后会创建一个新的8081端口容器,并创建一个8081镜像,并备份之前的镜像可以启用多个端口 结构  DockerFile#FROM#基础镜像,当前新镜像是基于哪个镜像的#MAINTAINER#镜像维护者的姓名混合邮箱地址#RUN#容器构建时需......
  • 010-BUG: org.springframework.cglib.core.CodeGenerationException: java.lang.refle
    参考:Unabletomakeprotectedfinaljava.lang.Classjava.lang.ClassLoader.defineClass-CSDN博客1.完整报错:"msg":"org.springframework.cglib.core.CodeGenerationException:java.lang.reflect.InaccessibleObjectException-->Unabletomakeprotect......
  • 2024年金九银十最新版Java面试题及答案整理(持续更新)
    2024年金九银十到了,发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全~这套互联网Java工程师面试题包括了:MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、Java面试、Spring、微服务、Linux、Springboot、SpringCloud、MQ、Kafka面试专......
  • Java-数据结构-二叉树-基础 (o゚▽゚)o
    文本目录:❄️一、树形结构:  ▶ 1、概念:▶ 2、特殊的概念: ▶ 3、树的表示形式:❄️二、二叉树:  ▶ 1、概念:   ▶2、两种特殊的二叉树:     ➷1)、满二叉树:      ➷ 2)、完全二叉树:  ▶3、二叉树的性质:    ➷ 1)性质一:  ......
  • 5-【JavaWeb】JUnit 单元测试及JUL 日志系统
    1.使用JUnit进行单元测试JUnit是Java中非常流行的单元测试框架,MyBatis与JUnit可以很好地结合,来测试持久层代码的正确性。1.1添加JUnit依赖在使用JUnit之前,需要在pom.xml中引入JUnit依赖。<dependency><groupId>junit</groupId><artifactId>......