学java学到 hashset 有不懂 的地方,求助!

时间:2022-08-01 16:48:06
不明白的地方是到底是谁调用了   hashCode()    和   equals(Object obj)

下面是代码

-------------------------------------------------------------------------------------------------------------------------------------------

package com.kk.Collection;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetTest {
    public static void main(String[] args) {
        Set hashSet=new HashSet();
        hashSet.add(new Student(0,"kk"));
        hashSet.add(new Student(1,"mm"));
        hashSet.add(new Student(1,"mm"));//内存地址和值一样,Set将不会添加同样的对象
        Iterator it=hashSet.iterator();
        while(it.hasNext()){
            Student stu=(Student) it.next();
            System.out.println(stu.name);
        }
    }

    static class Student {
        int num;

        String name;

        public Student(int num, String name) {
            this.num = num;
            this.name = name;
        }

        @Override
        /**
         * 判断对象的内存地址是否一样
         */
        public int hashCode() {
            return num*name.hashCode();
        }

        @Override
        /**
         * 判断对象的值是否一样
         */
        public boolean equals(Object obj) {
            Student stu=(Student) obj;
            return this.num==stu.num && this.name.equals(stu.name);
        }
    }
}

7 个解决方案

#1


HashSet在你调用add的时候,就会调用添加的对象的hashCode方法,而equals方法是在你某些操作的时候,比如remove,HashSet来判断到底是哪一个对象所调用的方法

#2


你去看JDK的源码就知道了!

#3


看看源码就什么都知道了。

#4



    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    public boolean add(E e) {
return map.put(e, PRESENT)==null;
    }

这是 hashset 代码中的一部分,hashset 底层是用hashmap来存储的,hashset 存储的值  存放到map中的key,value值 就是PRESENT(一个模拟值而已)。这你就该明白了吧,hashMap的 key 是不能,也不会重复的,hashmap的源码是怎么实现 key不能重复的机制,就是 set集合不能重复的实现。

#5


简单点给你说,add的时候调用equals,在你查找的时候调用hashcode,所以hashcode写得好坏会影响查找效率。

#6


下面是我自己的代码练习和理解,不知道是不是你需要的
===================================================================================
package com.test.example;

import java.util.HashSet;

class Student /*extends Object*/{ //Object是所有自定义类的父类
//hashCode和equals方法是Object中已定义的方法,所有类都有这两个方法
int Sno;
String Sname = null;
public Student(int Sno, String Sname){
this.Sno = Sno;
this.Sname = Sname;
}
//hashCode先被调用,如果在集合中有与当前元素一致的hashCode,调用equals进一步比对
//1.需要重写一个方法hashCode(哈希码)
public int hashCode(){
System.out.println("生成hashCode"); //添加元素时自动调用hashCode
return Sno;
}
//2.重写equals方法
public boolean equals(Object obj){
Student s = (Student)obj;
System.out.println("equals被调用 [" + Sname + "] -- [" + s.Sname + "] ");
boolean b = Sno == s.Sno;
//boolean b = Sname.equals(s.Sname);
return b; //返回true表示一致
}


}
public class StudentSet {
public static void main(String[] args){
/**当使用HashSet存储自定义类时,需要在自定义类中重写equals和hashCode方法,
 * 主要原因是集合内不允许有重复的数据元素,在集合校验元素的有效性时(数据元素不可重复),
 * 需要调用equals和hashCode验证。
 * */
HashSet<Student> stuSet = new HashSet<Student>();
Student s1 = new Student(1, "Lily");
Student s2 = new Student(2, "Tom");
Student s3 = new Student(3, "Jay");
Student s4 = new Student(3, "Jay");
/*stuSet.add(s1);
stuSet.add(s2);
stuSet.add(s3);
stuSet.add(s4);
//System.out.println(stuSet);
//因为没有重写toString方法,所以返回Object默认toString,显示的是元素的位置
System.out.println("stuSet的大小是:" + stuSet.size());//重写之前,stuSet的大小是:4
//s3和s4一样,但是stuSet将其视作两个元素
//因为Student是自定义类,Set不能判断自定义类什么时候重复,所以需要重写hashCode方法和equals方法
*/
System.out.println("-------------------0-------------------");
stuSet.add(s1);
System.out.println("-------------------1-------------------");
stuSet.add(s2);
System.out.println("-------------------2-------------------");
stuSet.add(s3);
System.out.println("-------------------3-------------------");
stuSet.add(s4);
System.out.println("-------------------4-------------------");
System.out.println("stuSet的大小是:" + stuSet.size());
/*结果显示:
                        -------------------0-------------------
生成hashCode
-------------------1-------------------
生成hashCode
-------------------2-------------------
生成hashCode
-------------------3-------------------
生成hashCode
equals被调用 [Jay] -- [Jay] 
-------------------4-------------------
stuSet的大小是:3
 * */
//当将自定义类的对象存储到set中时,会先自动调用hashCode,如果不一致,直接添加元素(不调用equals方法)
//当hashCode一致时,再调用equals进行比较,如果不一致添加元素,如果一致则舍弃
}
}

#7


不知道API介绍的方法底层大致什么逻辑,就看源码吧! 学java学到 hashset 有不懂 的地方,求助!

#1


HashSet在你调用add的时候,就会调用添加的对象的hashCode方法,而equals方法是在你某些操作的时候,比如remove,HashSet来判断到底是哪一个对象所调用的方法

#2


你去看JDK的源码就知道了!

#3


看看源码就什么都知道了。

#4



    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    public boolean add(E e) {
return map.put(e, PRESENT)==null;
    }

这是 hashset 代码中的一部分,hashset 底层是用hashmap来存储的,hashset 存储的值  存放到map中的key,value值 就是PRESENT(一个模拟值而已)。这你就该明白了吧,hashMap的 key 是不能,也不会重复的,hashmap的源码是怎么实现 key不能重复的机制,就是 set集合不能重复的实现。

#5


简单点给你说,add的时候调用equals,在你查找的时候调用hashcode,所以hashcode写得好坏会影响查找效率。

#6


下面是我自己的代码练习和理解,不知道是不是你需要的
===================================================================================
package com.test.example;

import java.util.HashSet;

class Student /*extends Object*/{ //Object是所有自定义类的父类
//hashCode和equals方法是Object中已定义的方法,所有类都有这两个方法
int Sno;
String Sname = null;
public Student(int Sno, String Sname){
this.Sno = Sno;
this.Sname = Sname;
}
//hashCode先被调用,如果在集合中有与当前元素一致的hashCode,调用equals进一步比对
//1.需要重写一个方法hashCode(哈希码)
public int hashCode(){
System.out.println("生成hashCode"); //添加元素时自动调用hashCode
return Sno;
}
//2.重写equals方法
public boolean equals(Object obj){
Student s = (Student)obj;
System.out.println("equals被调用 [" + Sname + "] -- [" + s.Sname + "] ");
boolean b = Sno == s.Sno;
//boolean b = Sname.equals(s.Sname);
return b; //返回true表示一致
}


}
public class StudentSet {
public static void main(String[] args){
/**当使用HashSet存储自定义类时,需要在自定义类中重写equals和hashCode方法,
 * 主要原因是集合内不允许有重复的数据元素,在集合校验元素的有效性时(数据元素不可重复),
 * 需要调用equals和hashCode验证。
 * */
HashSet<Student> stuSet = new HashSet<Student>();
Student s1 = new Student(1, "Lily");
Student s2 = new Student(2, "Tom");
Student s3 = new Student(3, "Jay");
Student s4 = new Student(3, "Jay");
/*stuSet.add(s1);
stuSet.add(s2);
stuSet.add(s3);
stuSet.add(s4);
//System.out.println(stuSet);
//因为没有重写toString方法,所以返回Object默认toString,显示的是元素的位置
System.out.println("stuSet的大小是:" + stuSet.size());//重写之前,stuSet的大小是:4
//s3和s4一样,但是stuSet将其视作两个元素
//因为Student是自定义类,Set不能判断自定义类什么时候重复,所以需要重写hashCode方法和equals方法
*/
System.out.println("-------------------0-------------------");
stuSet.add(s1);
System.out.println("-------------------1-------------------");
stuSet.add(s2);
System.out.println("-------------------2-------------------");
stuSet.add(s3);
System.out.println("-------------------3-------------------");
stuSet.add(s4);
System.out.println("-------------------4-------------------");
System.out.println("stuSet的大小是:" + stuSet.size());
/*结果显示:
                        -------------------0-------------------
生成hashCode
-------------------1-------------------
生成hashCode
-------------------2-------------------
生成hashCode
-------------------3-------------------
生成hashCode
equals被调用 [Jay] -- [Jay] 
-------------------4-------------------
stuSet的大小是:3
 * */
//当将自定义类的对象存储到set中时,会先自动调用hashCode,如果不一致,直接添加元素(不调用equals方法)
//当hashCode一致时,再调用equals进行比较,如果不一致添加元素,如果一致则舍弃
}
}

#7


不知道API介绍的方法底层大致什么逻辑,就看源码吧! 学java学到 hashset 有不懂 的地方,求助!