HashSet常用方法介绍

public boolean add(E e)
public boolean isEmpty()
void clear()
public Iterator<E> iterator()
int size()

详细方法详见JDK帮助文档

Object的equals方法和hashCode方法

1、 Object类equals方法的特点:

  a) 自反性:x.equals(x)应该返回true

  b) 对称性:x.equels(y)为true,那么y.equals(x)也为true

  c) 传递性:x.equels(y)为true并且y.equels(z)为true,那么x.equels(z)也应该为true

  d) 一致性:x.equels(y)的第一次调用为true,那么x.equels(y)的第二次、第三次、第n次调用也应该为true,前提条件是在比较之间没有修改x也没有修改y

  e) 对于非空引用x,x.equels(null)返回false

2、 Object类hashCode方法的特点:

  a) 在java应用的一次执行过程中,对于同一个对象的hashCode方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化);

  b) 对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的

  c) 对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象的hashCode值不要求一定不同(可以相同,也可以不同),但是如果不同则可以提高应用的性能;

  d) 对于Object类来说,不同Object对象的hashCode的值是不同的(Object类的hashCode值表示的是对象的地址);Object的toString()方法默认调用的是:

getClass().getName() + '@' + Integer.toHexString(hashCode())

3、 如果我们重写equals方法,那么也要重写hashCode方法,反之亦然;

HashSet常用方法源码分析

构造方法

public HashSet() {
map = new HashMap<E,Object>();
} private transient HashMap<E,Object> map;

add()

public boolean add(E e) {
return map.put(e, PRESENT)==null;
} private static final Object PRESENT = new Object(); //同一个set中的PRESENT对象一致

remove()

public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}

size()

public int size() {
return map.size();
}

iterator ()

public Iterator<E> iterator() {
return map.keySet().iterator();
}

常用方法源码分析总结

1、 set可以添加null;

2、 在使用HashSet时,hashCode()方法会得到调用,判断已经存储在集合中的对象的hashCode值是否与添加的对象的hashCode值一致,如果不一致,直接添加进去;如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经添加进去了,就不会再添加新的对象,否则就加进去;

3、 HashSet底层是使用HashMap实现的,当调用add方法将对象添加到Set中时,实际上是将该对象作为底层所维护的Map对象的key,而value则都是同一个Object对象(该对象我们用不上)。在HashMap中,同一个key,后添加的value会覆盖前一个value;

4、 当重写equals方法的时候必须要重写hashCode方法,如果一个类的两个对象的equals方法比较结果为true,那么该两个对象必须具有相同的hashCode值

HashSet示例分析

示例1:添加两个相同的对象

public class HashSetDemo03 {
public static void main(String[] args) {
HashSet set = new HashSet();
People p1 = new People("zhangsan");// p1存放的是zhangsan的引用地址 set.add(p1);
set.add(p1);
System.err.println(set);
}
} public class People {
String name;
public People(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}

分析:当往set中添加Person对象的时候,先添加进去p1,在第二次还是添加p1的时候,会先调用hashCode方法(同一对象的hashCode值当然相同),再去判断equals()方法,同一对象的equals()方法肯定是true的,所以加不进去。

示例2:添加两个相同的字符串

public class HashSetDemo04 {
public static void main(String[] args) {
HashSet set = new HashSet();
String s1 = new String("a");
String s2 = new String("a");
set.add(s1);
set.add(s2);
System.out.println(set);
}
}

分析:当往set中添加是s1的时候,先添加进去s1,在第二次还是添加s1的时候,会先调用hashCode方法,String对象已经重写了hashCode()方法(根据给定的字符串用一个公式运算),hashCode值是相同的,再去判断equals()方法,String的equals()方法比较的是字符串的内容,所以equals()为true,所以加不进去。

示例3:重写equals和hashcode后对比

public class HashSetDemo05 {
public static void main(String[] args) {
HashSet set = new HashSet();
Student s1 = new Student("zhangsan");
Student s2 = new Student("zhangsan");
set.add(s1);
set.add(s2);
System.out.println(set);
}
}
public class Student {
String name;
public Student(String name) {
this.name = name;
}
public String toString() {
return name;
}
}

分析:

未重写equals和hashcode方法之前:s1和s2是不同的两个对象,由于hashCode存放的是引用的地址,所以他们是不同的,就直接加进去了。

重写equals()和hashCode()方法之后,hashCode就按照name进行取值,所以他们的hashCode相等,然后比较equals()方法,而我们自己也按照name重写了equals()方法。所以equals为true,就不会加进去。

    @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}

示例3:HashSet常用迭代方法

public class HashSetDemo06 {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e"); Iterator iter = set.iterator();
while (iter.hasNext()) {
String value = (String) iter.next();
System.out.println(value);
} System.out.println("--------------"); for (Iterator iterator = set.iterator(); iterator.hasNext();) {
String s = (String) iterator.next();
System.out.println(s);
}
}
}

TreeSet

HashSet是在输出的时候是没有顺序的,而TreeSet是能够按照指定的顺序进行输出的。

TreeSet的构造方法

public TreeSet(Comparator<? super E> comparator)

在构造方法中需要我们事先自定义好一个实现Comparator接口的方法,并重写它的int compare(T o1,T o2)方法。

如何定义自己的Comparator

public class TreeSetDemo02 {
public static void main(String[] args) {
TreeSet<Order> set = new TreeSet<Order>(new OrderComparator());
set.add(new Order(10));
set.add(new Order(20));
set.add(new Order(30));
set.add(new Order(40)); for (Order order : set) {
System.out.println(order);
}
}
} class OrderComparator implements Comparator<Order> {
@Override
public int compare(Order o1, Order o2) {
return -(o1.count - o2.count);
}
} class Order {
int count;
public Order(int count) {
this.count = count;
}
public String toString() {
return String.valueOf(count);
}
}

我们可以在OrderComparator类中的compare方法中按照自己的意愿进行重写以实现升序或者降序排列。

public class TreeSetDemo03 {
public static void main(String[] args) {
TreeSet set = new TreeSet(new MyComparator());
set.add("A");
set.add("F");
set.add("E");
set.add("D");
set.add("a");
set.add("C");
set.add("B");
for (Iterator iterator = set.iterator(); iterator.hasNext();) {
String s = (String) iterator.next();
System.out.println(s);
}
}
} class MyComparator implements Comparator {
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
return -s1.compareTo(s2);
}
}

我们可以在MyComparator类中的compare方法中按照字母的降序排列。

jdk集合常用方法分析之HashSet和TreeSet的更多相关文章

  1. jdk集合常用方法分析之ArrayList&LinkedList&以及两者的对比分析

    集合使用注意事项: 1.集合当中只能放置对象的引用,无法放置原生数据类型,我们需要使用原生数据类型的包装类才能加入到集合当中去(JDK5之后会进行自动的装箱和拆箱操作,表面上看集合中是可以直接放置原生 ...

  2. java集合系列——Set之HashSet和TreeSet介绍(十)

    一.Set的简介 Set是一个不包含重复元素的 collection.更确切地讲,set 不包含满足 e1.equals(e2) 的元素.对 e1 和 e2,并且最多包含一个为 null 的元素. S ...

  3. JDK源码分析(五)——HashSet

    目录 HashSet概述 内部字段及构造方法 存储元素 删除元素 包含元素 总结 HashSet概述   从前面开始,已经分析过集合中的List和Map,今天来介绍另一种集合元素:Set.这是JDK对 ...

  4. (9)集合之Set,HashSet,TreeSet

    TreeSet子类 注意事项: 1.向TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储 2.往TreeSet添加元素的时候,如果元素本身不具备自 ...

  5. JDK源码学习笔记——HashSet LinkedHashSet TreeSet

    你一定听说过HashSet就是通过HashMap实现的 相信我,翻一翻HashSet的源码,秒懂!! 其实很多东西,只是没有静下心来看,只要去看,说不定一下子就明白了…… HashSet 两个属性: ...

  6. Java集合源码分析(六)TreeSet<E>

    TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, j ...

  7. Java集合详解7:HashSet,TreeSet与LinkedHashSet

    今天我们来探索一下HashSet,TreeSet与LinkedHashSet的基本原理与源码实现,由于这三个set都是基于之前文章的三个map进行实现的,所以推荐大家先看一下前面有关map的文章,结合 ...

  8. HashSet LinkedHashSet TreeSet 分析

    1.HashSet分析 hashset 底层是hash表,就是hashMap,是无序的,唯一的.也就是说,它的底层其实就是一个HashMap  key 值的组成值.所以具有唯一性. public Ha ...

  9. Java集合系列(三):HashSet、LinkedHashSet、TreeSet的使用方法及区别

    本篇博客主要讲解Set接口的三个实现类HashSet.LinkedHashSet.TreeSet的使用方法以及三者之间的区别. 注意:本文中代码使用的JDK版本为1.8.0_191 1. HashSe ...

随机推荐

  1. flume ng 问题点

    1. 启动Flume,出现脚本错误 错误如下: bin/flume-ng: line 82: syntax error in conditional expression: unexpected to ...

  2. Android 不同文件名介绍

    Android 不同文件名介绍

  3. C# Redis实战(二) [转]

    二.Redis服务  在C# Redis实战(一)中我将所有文件拷贝到了D盘redis文件夹下,其中redis-server.exe即为其服务端程序,双击即开始运行,如图               ...

  4. 08socket编程

    有个SO_REUSEADDR值得注意一下: 服务器端尽可能使用SO_REUSEADDR 在绑定之前尽可能调用setsockopt来设置SO_REUSEADDR套接字选项. 使用SO_REUSEADDR ...

  5. Force IE to Open Link in New Tab

    1.First, open Internet Explorer and click on Tools and then Internet Options. 2.Now click on the Set ...

  6. 【maven】之使用jetty发布web项目

    <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin ...

  7. 关于AVD无法使用问题

    因为工作需要,刚入手android,搭建开发环境挺麻烦,整个环境的搭建配置我就不说了,网上很多,这里就只说一下我遇到的一个问题. Java JDK安装完毕,环境变量配置完毕,eclipse下载好后解压 ...

  8. c/c++多线程编程中最好不要加volatile

    来自https://www.zhihu.com/question/31459750 答主解释说:不能指望volatile能解决多线程竞争问题,除非所用的环境系统不可靠才会为了保险加上volatile, ...

  9. 在eclipse中设计BPMN 2.0工作流定义的根本步骤

    原文地址:http://www.myexception.cn/eclipse/1863140.html 在eclipse中设计BPMN 2.0工作流定义的基本步骤 1. Activiti问我们提供了A ...

  10. 黄聪:VS2010开发如何在c#中使用Ctrl、Alt、Tab等全局组合快捷键

    1.新建一个类 HotkeyHelper  using System; using System.Runtime.InteropServices; using System.Windows.Forms ...