set -> hashset treeset
set集合最最重要的一个特征就是, 自动去重 -- hashCode方法与equals方法
treeset中弥补了hashset无序的缺点, 但是代价是消耗的性能比hashset高, 比hashset执行更慢一些
HashSet
核心特性
特点1: HashSet当中存储的数据是无序的.
特点2: HashSet中存储的数据是不重复的. (重点)
重复指的是, 两个对象调用equals返还true, 并且两个对象的hashCode方法返还的结果相等
重复的意思, 指的是两个数据完全相等
HashSet方法和TreeSet方法基本相同
HashSet(散列存放的子类)
* 1.无序: 跟放入顺序无关,结果也是无序的
* 2.元素不允许重复
*
*
* 跟TreeSet不同 放入元素 尽管没有实现比较器 也不会报错 但是没有实现查重规则
* 所以HashSet的查重规则(因为没有大小比较)不是比较器
* 那么HashSet的查重规则到底是什么呢?
*
* 先调用hashCode方法 再调用equals方法进行比较
*
*
*
*HashSet集合再放入引用数据类型是 需要进行查重比较 查重的规则是先
*调用hashCode方法 如果hashCode方法相等 则再去调用equals方法 进行各项属性的比较
* 如果hashCode方法不相等 则判定两个对象不相等
*
*第一步:
*hashCode:
* 什么是hashCode方法:在Object类中定义的,默认的功能是返回当前对象跟地址值相关的一串数据(无意义)
* 那么需要我们自己覆写,覆写要实现什么样子有意义的功能呢?
* 为什么HashSet集合在放入对象时 要先比较hashCode方法 再去比较equals方法呢?直接调用equals去比较对象是否相等不就好了么?
* equals方法是对象和对象之间进行各项属性的比较 从而判断两个对象是否相等,所以效率非常低下
*
* 所以要先调用hashCode方法 进行非常效率的比较,也就是先快速比较出两个对象是否相等,
* 一旦hashCode方法比较出两个对象不相等了,那就不用去调用equals方法了 提高了效率
* 如果hashCode无法判断出这两个对象是否相等 那么就要请出我们的大哥equals方法 进行各项属性的比较了
*
*
*hashCode方法到底是什么代码?应该实现什么功能呢?
*实现根据各项属性值 动态计算出一个哈希码
*例如: age*5+name.length*3
*先进行每一个对象的哈希码比较,一旦hashCode返回值 也就是哈希码不相等 那么两个对象必然不相等,那么比较出结果,
不需要再调用equals方法
*如果hashCode返回值也就是哈希码相等,并不能说明 两个对象一定相等,因为不同的数值经过同样的算法有可能算出同样结果
*所以这个时候就要用equals方法 进行各项属性的比较 看看是否每一个属性都相等
*
*
*
*
*
*第二步:
*equasl:
* 进行各项属性的详细比较
*
*
*
* 先比较hashCode方法是为了提高比较效率
* 后用equals比较 是为了提高比较的准确率
*
* 那么我们如果不覆写这两个方法 HashSet不会报错 ,但是也没有实现查重 为什么?
* 因为如果我们没覆写,那么调用是父类Object的hashCode方法,而Object的hashCode方法返回地址值
* 只要是新创建出来的对象 地址必然不相等
* 那么如果地址相等了 hashSet还会去调用equals方法,那么此时我们依然没覆写,调用的是Obejct类的
* Object类的equals是进行==比较 比较地址
*
* 所以我们必须进行两个方法的合理覆写,定义我们想要比较的规则
*
*
* TreeSet和HashSet的区别
*
* 共同点:
* 无序:跟元素的放入顺序无关
* 没有角标
* 遍历方式
*
* TreeSet:
* 结果是排序的
* 排序规则是比较器
* 不允许出现null值
*
*
*
*
* HashSet:
* 结果是无序的
* 查重规则是hashCode和equals
* 可以有null值 多个null视为重复 只能出现一个
public class HashSetDemo { /** * TreeSet的常用方法 * * 1. 有序 和存放的代码的执行顺序无关, 和这个对象的compareTo方法有关 * 2. 去重 和hashset一样, 是自动去重的 * @param args */ public static void main(String[] args) { TreeSet<String> java22 = new TreeSet<>(); // 根据ASCII码值进行排序的 java22.add("gp"); java22.add("ml"); java22.add("bw"); java22.add("ba"); java22.add("xk"); java22.add("xk"); // TreeSet<Integer> java22 = new TreeSet<>(); // // java22.add(400); // java22.add(200); // java22.add(300); // java22.add(100); System.out.println(java22); } /** * 核心方法add() * HashSet的其他方法 hashset虽然是属于list, 但是所有的带有角标的方法全部都没有了, 因为无序 * @param args */ public static void main4(String[] args) { // 增删改查 HashSet<String> java22 = new HashSet<>(); java22.add("浩远"); java22.add("兴宇"); // 删 // java22.remove("浩远"); // 修改 // 如果想要将浩远 -> 屠恩侠 // java22.remove("浩远"); // java22.add("屠恩侠"); // 查询数据 只能通过遍历的方式查询所有数据 // 1. 通过迭代器遍历 // Iterator<String> iterator = java22.iterator(); // while (iterator.hasNext()){ // System.out.println(iterator.next()); // } // 2. 所有能够通过迭代器遍历的方式, 都可以用增强for循环替代 // 当对集合中的数据不做删除或者新增的时候, 使用增强for循环更加简洁 // 当对集合中的数据做删除或者新增的时候, 使用迭代器, 避免一遍遍历一遍修改的bug for (String name: java22){ System.out.println(name); } // System.out.println(java22); // hashset的其他方法 // System.out.println(java22.contains("高鹏")); // 获取set集合存储的数据的大小 // System.out.println(java22.size()); } /** * HashSet存储的数据是无序的 (了解) * * 1. HashSet方法有序或者无序 和 hashCode方法极度相关 * 2. HashSet中的对象的存储 和 hashCode值 是否是 值大的存储在后面的位置 * * 2. HashSet中对象存储 和 hashCode值相关 * hashCode值和15做&位运算, 将得到的结果, 结果越大的存储在越后面 * 扩展(纯了解 后面会说): 15这个数字随着HashSet中的数据的增多, 会逐步扩充两倍 * @param args */ public static void main3(String[] args) { // System.out.println(16 & 15); // System.out.println(17 & 15); // System.out.println(18 & 15); // System.out.println(11 & 15); // System.out.println(12 & 15); // System.out.println(13 & 15); // System.out.println(14 & 15); // System.out.println(15 & 15); HashSet<Student> java22 = new HashSet<>(); java22.add(new Student("刘威", 100, 18)); //3 java22.add(new Student("高鹏", 100, 17)); //2 java22.add(new Student("欣凯", 100, 16)); //1 java22.add(new Student("博文", 100, 15)); //8 java22.add(new Student("屠恩侠", 100, 14)); //7 java22.add(new Student("屠恩侠1", 100, 13)); //6 java22.add(new Student("屠恩侠2", 100, 12)); //5 java22.add(new Student("屠恩侠3", 100, 11)); //4 System.out.println(java22); } /** * HashSet去重是如何完成的 (重要) * 去重的关键在于, 判断两个对象是否相同 * 1. hashCode方法 * 2. equals方法 * equals方法如果不重写的话, 判断标准是地址值是否相同 * hashCode方法如果不重写的话, 返回的int值是当前对象的地址值 * * HashSet如何判定两个对象是否重复, 需要同时满足两个条件 * 1. 两个对象的hashCode值相同 * 2. 两个对象调用equals方法, 返还的是true * * @param args */ public static void main2(String[] args) { HashSet<Student> java22 = new HashSet<>(); // 我们已经改写定义了重复, 没有重写equals之前, 重复指的是 地址值相同 // 现在, 指的是, 所有属性值, 姓名, 年龄, 成绩的值都相等 Student liuWei1 = new Student("刘威", 100, 18); Student liuWei2 = new Student("刘威", 100, 18); System.out.println(liuWei1.equals(liuWei2)); System.out.println("刘威1和2的hashcode值"); System.out.println(liuWei1.hashCode()); System.out.println(liuWei2.hashCode()); java22.add(liuWei1); java22.add(liuWei2); System.out.println(java22); } /** * HashSet的基本方法 * @param args */ public static void main1(String[] args) { // HashSet<String> java22 = new HashSet<>(); // // java22.add("刘威"); // java22.add("高鹏"); // java22.add("浩远"); // java22.add("欣凯"); // java22.add("刘威"); // // System.out.println(java22); HashSet<Student> java22 = new HashSet<>(); java22.add(new Student("刘威", 100, 18)); java22.add(new Student("刘威", 100, 18)); System.out.println(java22); } }
标签:System,java22,HashSet,重复,无序,hashCode,add,println From: https://www.cnblogs.com/p1121/p/17010167.html