简单的理解java集合中的HashSet和HashTree几个重写方法

Java中的set是无序的,但是是不可重复的

HashSet底层是哈希表,通过调用hashcode和equals方法实现去重

当我们HashSet里面存的是字符串时,就能默认去重了,因为String已经重写了hashcode和euqals方法

  public static void main(String[] args) {
    HashSet<String> set = new HashSet();
    set.add("java");
    set.add("c");
    set.add("php");
    set.add("bigdata");
    set.add("java");
    //运行结果,给去重了,而且是无序的
    System.out.println(set);//[java, c, bigdata, php]
  }
}

但是当我们有类的时候,比如Person,Cat,Dog,我们自己写的类,但是我们想按照自己制定的规则去重,就比如Person的姓名和年龄,因为Person类是我们自己建的,如果我们没有重写方法,就会去找Object的hashcode方法,这样new Person()的hashcode就会不同,这样每个都是一个新的,都会输出,即使年龄和姓名一样

public class Demo1 {
  public static void main(String[] args) {
    HashSet<Person> set1 = new HashSet<>();
    set1.add(new Person("aing",50));
    set1.add(new Person("bing",10));
    set1.add(new Person("ding",20));
    set1.add(new Person("ding",20));
    //运行结果是即使名字年龄一样,也会输出两个,我们如果想要按照自己的规则去重,这样我们一定要重写hashcode 和euqals方法
    System.out.println(set1);//[Person{name='bing', age=10}, Person{name='ding', age=20}, Person{name='aing', age=50}, Person{name='ding', age=20}]
  }
}
class Person{
  String name;
  int age;

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

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

我们重写hashcode方法,当hashcode不一样时,就不会比较equals,直接就是不一样,如果hashcode一样,再比较equals方法

public class Demo1 {
  public static void main(String[] args) {
    HashSet<Person> set1 = new HashSet<>();
    set1.add(new Person("aing",50));
    set1.add(new Person("bing",10));
    set1.add(new Person("ding",20));
    set1.add(new Person("ding",20));
    //根据年龄和姓名比较的
    System.out.println(set1);//[Person{name='ding', age=20}, Person{name='aing', age=50}, Person{name='bing', age=10}]
  }
}
class Person{
  String name;
  int age;
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  @Override
  public String toString() {
    return "Person{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
  }
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person person = (Person) o;
    return age == person.age &&
        Objects.equals(name, person.name);
  }
  //和属性关联,根据属性的值比较,之所以让age*100;是因为怕有可能出现这个name.hashCode()+age 和 下一个name.hashCode()+age加起来的值恰好相等,所以age*100,可以避免这种情况的发生
  @Override
  public int hashCode() {
    //return Objects.hash(name, age);
    return name.hashCode()+age*100;
  }
}

TreeSet底层是二叉树,而且TreeSet还是有序的,在String中不仅重写了hashcode,还要调用元素的compareTo方法, String类已经实现了Comparable接口,并重写 了compareTo方法,但是如果我们自己写类的话,比如Person来说,如果想要按照自己的规则比,就要重写hashcode方法和实现Comparable接口

public class Demo2 {
  public static void main(String[] args) {
    TreeSet<String> set = new TreeSet();
    set.add("java");
    set.add("c");
    set.add("php");
    set.add("bigdata");
    set.add("java");
    System.out.println(set);//[bigdata, c, java, php]
  }
}

但是要是自己的类
会报错cannot be cast to java.lang.Comparable,因为Person会去找compareTo的方法,但是Person类没有实现它,我们要去实现Comparable

public class Demo2 {
  public static void main(String[] args) {
    TreeSet<Person1> set1 = new TreeSet<>();
    set1.add(new Person1("aing",50));
    set1.add(new Person1("bing",10));
    set1.add(new Person1("ding",20));
    set1.add(new Person1("ding",20));
    System.out.println(set1);
  }
}
class Person1{
  String name;
  int age;

  public Person1(String name, int age) {
    this.name = name;
    this.age = age;
  }

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

这样我们就可以实现有序了,根据我们的属性

public class Demo2 {
  public static void main(String[] args) {
    TreeSet<Person1> set1 = new TreeSet<>();
    set1.add(new Person1("aing",50));
    set1.add(new Person1("bing",10));
    set1.add(new Person1("ding",20));
    set1.add(new Person1("ding",20));
    System.out.println(set1);
  }
}
class Person1 implements Comparable{
  String name;
  int age;

  public Person1(String name, int age) {
    this.name = name;
    this.age = age;
  }

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

  @Override
  public int hashCode() {
    return name.hashCode()+age*100;
  }

  @Override
  public String toString() {
    return "Person1{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
  }
  //根据类的属性进行排序
  @Override
  public int compareTo(Object o) {
  Person1 person = (Person1)o;
  int num = name.compareTo(person.name);
  return num==0?age-person.age:num;
}
}

到此这篇关于简单的理解java集合中的HashSet和HashTree几个重写方法的文章就介绍到这了,更多相关java HashSet和HashTree重写内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-10-12

HashSet工作原理_动力节点Java学院整理

对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如下代码: public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { // 使用 HashMap 的 key 保存 HashSet 中

Java中HashSet和HashMap的区别_动力节点Java学院整理

什么是HashSet? HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象.如果我们没有重写这两个方法,将会使用这个方法的默认实现.. public boolean add(Object o)方法用来在Set中添加元素,当元素值重复时则会立即返回false,如果成功添加的话会返回true. 什

java 中HashMap、HashSet、TreeMap、TreeSet判断元素相同的几种方法比较

java 中HashMap.HashSet.TreeMap.TreeSet判断元素相同的几种方法比较 1.1     HashMap 先来看一下HashMap里面是怎么存放元素的.Map里面存放的每一个元素都是key-value这样的键值对,而且都是通过put方法进行添加的,而且相同的key在Map中只会有一个与之关联的value存在.put方法在Map中的定义如下. V put(K key, V value); 它用来存放key-value这样的一个键值对,返回值是key在Map中存放的旧va

详解Java中HashSet和TreeSet的区别

详解Java中HashSet和TreeSet的区别 1. HashSet HashSet有以下特点: 不能保证元素的排列顺序,顺序有可能发生变化 不是同步的 集合元素可以是null,但只能放入一个null 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置. 简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个

Java编程中的HashSet和BitSet详解

Java编程中的HashSet和BitSet详解 我在Apache的开发邮件列表中发现一件很有趣的事,Apache Commons包的ArrayUtils类的removeElements方法,原先使用的HashSet现在换成了BitSet. HashSet<Integer> toRemove = new HashSet<Integer>(); for (Map.Entry<Character, MutableInt> e : occurrences.entrySet()

Java编程思想对象的容纳实例详解

Java提供了容纳对象(或者对象的句柄)的多种方式,接下来我们具体看看都有哪些方式. 有两方面的问题将数组与其他集合类型区分开来:效率和类型.对于Java来说,为保存和访问一系列对象(实际是对象的句柄)数组,最有效的方法莫过于数组.数组实际代表一个简单的线性序列,它使得元素的访问速度非常快,但我们却要为这种速度付出代价:创建一个数组对象时,它的大小是固定的,而且不可在那个数组对象的"存在时间"内发生改变.可创建特定大小的一个数组,然后假如用光了存储空间,就再创建一个新数组,将所有句柄从

Java编程Webservice指定超时时间代码详解

WebService是一种跨编程语言和跨操作系统平台的远程调用技术 所谓远程调用,就是一台计算机a上的一个程序可以调用到另外一台计算机b上的一个对象的方法,譬如,银联提供给商场的pos刷卡系统(采用交互提问的方式来加深大家对此技术的理解). 远程调用技术有什么用呢?商场的POS机转账调用的转账方法的代码是在银行服务器上,还是在商场的pos机上呢?什么情况下可能用到远程调用技术呢?例如,amazon,天气预报系统,淘宝网,校内网,百度等把自己的系统服务以webservice服务的形式暴露出来,让第

Java语言中的内存泄露代码详解

Java的一个重要特性就是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己来释放内存.理论上Java中所有不会再被利用的对象所占用的内存,都可以被GC回收,但是Java也存在内存泄露,但它的表现与C++不同. JAVA中的内存管理 要了解Java中的内存泄露,首先就得知道Java中的内存是如何管理的. 在Java程序中,我们通常使用new为对象分配内存,而这些内存空间都在堆(Heap)上. 下面看一个示例: public class Simple { public static vo

Java编程实现快速排序及优化代码详解

普通快速排序 找一个基准值base,然后一趟排序后让base左边的数都小于base,base右边的数都大于等于base.再分为两个子数组的排序.如此递归下去. public class QuickSort { public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } public static <T extends Comparabl

Java编程构造方法与对象的创建详解

java构造方法与对象的创建 可以用类来声明对象,声明对象后必须创建对象 1构造方法 首先,我们来谈谈什么叫构造方法,既然都说了这是一个构造方法,那么很显然,它本质上就是一个方法. 那么,既然作为一个方法,它应该有方法的样子吧.它除了回调一个Class();之后,也没见它有其他的定义方法的代码呀?这是因为,在未对类自定义构造方法的情况下,编译器会自动在编译期为其添加默认的构造方法 (1)程序用类创建对象时,需要使用该类的构造方法 (2)类中构造方法的名字必须和类名完全相同,而且没有类型 (3)允

Java编程多线程之共享数据代码详解

本文主要总结线程共享数据的相关知识,主要包括两方面:一是某个线程内如何共享数据,保证各个线程的数据不交叉:一是多个线程间如何共享数据,保证数据的一致性. 线程范围内共享数据 自己实现的话,是定义一个Map,线程为键,数据为值,表中的每一项即是为每个线程准备的数据,这样在一个线程中数据是一致的. 例子 package com.iot.thread; import java.util.HashMap; import java.util.Map; import java.util.Random; /*

Java编程访问权限的控制代码详解

本文研究的主要是Java编程访问权限的控制的相关内容,具体介绍如下. 之前没去注意的修饰符,一般变量前面没添加,一个是不知道有什么用,一个是懒,后面遇到项目的时候就会发现私有和公有区别还是很大的. (1)首先是包名 使用一个类的时候,例如集合类,就需要引入这个包,然后再使用该包下面的类.如: package com.myown.iaiti; public class Print { static void print(String s){ System.out.println(s); } } 自

java web中对json的使用详解

一.在Java Web的开发过程中,如果希望调用Java对象转化成JSON对象等操作.则需要引入以下jar包,不然运行时则报错. 1.commons-beanutils.jar 2.commons-collections.jar 3.commons-lang.jar 4.commons-logging-1.1.jar 5.ezmorph-1.0.3.jar 6.json-lib-2.0-jdk15.jar 7.有人说还需要 commons-httpclient.jar 引入成功之后,使用JSON

Java编程实现非对称加密的方法详解

本文实例讲述了Java编程实现非对称加密的方法.分享给大家供大家参考,具体如下: 对称加密算法在加密和解密时使用的是同一个秘钥:而非对称加密算法需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥). 是一种 高级的双保险加密方式,一般的实现加密方式有DH密钥交换算法,RSA基于因子分解算法,ElGamal离散对数算法及ECC椭圆曲线加密等. DH加密解密 /** * 非对称加密之:DH加密 * 非对称DH,是安全性基于