jdk集合常用方法分析之HashSet和TreeSet
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,就不会加进去。
@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic 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> {@Overridepublic 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相关推荐
- Java—Set集合详解(HashSet/LinkedHashSet/TreeSet/EnumSet)
关注微信公众号:CodingTechWork,一起学习进步. Set集合介绍 Set集合的概念 Set集合类似于一个容器,程序把很多对象保存到Set集合中,Set集合对添加顺序不记录,当有重复的对 ...
- 1.4 Set集合:HashSet和TreeSet类
Set 集合 无序的,不能包含重复的对象 Set 集合类似于一个罐子,程序可以依次把多个对象"丢进"Set 集合,而 Set 集合通常不能记住元素的添加顺序. 也就是说 Set 集 ...
- 集合{LinkedHashMap TreeMap HashSet LinkedHashSet TreeSet 快速失败机制 ConcurrentHashMap CAS 多线程协同扩容}(二)
目录标题 LinkedHashMap Map集合框架结构体系图 什么是LinkedHashMap Linked 链式 的意思 HashMap "哈希映射"的意思 LinkedHas ...
- Java容器源码分析-HashSet vs TreeSet vs LinkedHashSet
2019独角兽企业重金招聘Python工程师标准>>> 这几天看了下容器的源码,总结一下HashSet vs TreeSet vs LinkedHashSet的区别, 如下图,col ...
- 三十九、Java集合中的HashSet和TreeSet
@Author:Runsen @Date:2020/6/6 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...
- 集合之Collection家族的 List接口+LinkedList+Vector+Stack及Set接口+HashSet+LinkedHashSet+TreeSet
集合之Collection家族的 List接口+LinkedList+Vector+Stack及Set接口+HashSet+LinkedHashSet+TreeSet 一.LinkedList 1.L ...
- java集合性能_Java集合性能分析-疯狂Java讲义
一.各Set实现类的性能分析 HashSet和TreeSet是Set的两个典型实现.HashSet的性能总是比TreeSet好(特别是最常用的添加.查询元素等操作),因为TreeSet需要额外的红黑树 ...
- 面试官系统精讲Java源码及大厂真题 - 11 HashSet、TreeSet 源码解析
11 HashSet.TreeSet 源码解析 更新时间:2019-09-16 19:37:35 成功的奥秘在于目标的坚定. --迪斯雷利 引导语 HashSet.TreeSet 两个类是在 Map ...
- Java集合性能分析-疯狂Java讲义
一.各Set实现类的性能分析 HashSet和TreeSet是Set的两个典型实现.HashSet的性能总是比TreeSet好(特别是最常用的添加.查询元素等操作),因为TreeSet需要额外的红黑树 ...
最新文章
- python语言教程-python基础教程
- ZeroC ICE的远程调用框架 代理引用地址
- [USACO5.3]校园网Network of Schools
- 60 分钟极速入门 PyTorch
- 红魔5S将配备320Hz游戏肩键:让小白瞬间成为操控高手
- linux查看虚拟化版本,4.15. 虚拟化 (机器翻译版本)
- java setcharat,Java StringBuilder setCharAt()方法
- 计算机视觉算法_RANSAC 估计
- Lasso估计学习笔记(二)
- python求一个数的因子_0是素数吗(python求一个数的因子)
- 用计算机术语形容人性格的词语,电脑桌创意广告词——关于电脑桌的广告语
- Matlab 乱码问题解决方法
- ChucK初步(13)
- Android 移动网络接入点名称(APN)
- 微信小程序判断手机号码格式正确与否的代码
- 手写数字识别问题实战
- 表格(table)属性cellspacing、cellpadding
- XTransfer外贸收款的六大优势是什么?
- 电镀废水除镍、电镀废水除总铬的工艺技术汇总分享
- PCA和SVD傻傻分不清楚?