从头认识java-15.3 使用HashSet须要注意的地方
这一章节我们来讨论一下使用Set的各种实现须要注意的地方。
Set接口的经常使用实现类有:HashSet。TreeSet,LinkedHashSet
1.HashSet
大家对于HashSet的印象都是它能够去除反复的元素,每个元素都是唯一的,可是这里面有一个前提。就是必须重写equals和hashcode方法。
大家的印象大都是以下这个:
package com.ray.ch15;
import java.util.HashSet;
public class Test {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
set.add(3);
for (int i = 0; i < 10; i++) {
set.add(i);
}
System.out.println(set);
}
}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
事实上当中的原因是,set里面的equals和hashcode方法都继承了Object里面的。而Object里面的这两个方法刚好能够比較easy的对照java的基础类型,甚至java里面大部分的类型。由于大部分类型都已经重写了equals和hashcode方法。
那么,我们以下自己定义一下自己的类型看看:
package com.ray.ch15; import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set; public class Test<T> {
public static <T> Set<T> fill(Set<T> set, Class<T> type)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, SecurityException,
InvocationTargetException, NoSuchMethodException {
for (int i = 0; i < 10; i++) {
set.add(type.getConstructor(int.class).newInstance(i));
}
return set;
} public static <T> void test(Set<T> set, Class<T> type)
throws IllegalArgumentException, SecurityException,
InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
fill(set, type);
fill(set, type);
fill(set, type);
System.out.println(set);
} public static void main(String[] args) throws IllegalArgumentException,
SecurityException, InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
test(new HashSet<SetType>(), SetType.class);
test(new HashSet<HashType>(), HashType.class);
}
} class SetType {
private int id = 0; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public SetType(int i) {
id = i;
} @Override
public String toString() {
return id + "";
} @Override
public boolean equals(Object obj) {
return obj instanceof SetType && (id == ((SetType) obj).id);
}
} class HashType extends SetType { public HashType(int i) {
super(i);
} @Override
public int hashCode() {
return getId();
}
}
输出:
[6, 6, 3, 4, 9, 5, 2, 9, 1, 7, 5, 4, 1, 2, 9, 3, 7, 8, 8, 0, 2, 0, 4, 6, 7, 5, 0, 1, 3, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
解释一下上面的代码:
(1)fill方法:通过泛型和反射。往传进来的set里面加入数据
(2)test方法:我们通过多次的往set里面填充数据,看看set是否去重
(3)SetType:原始类型,仅仅是简单实现了equals方法和toString方法,toString这里通过输出id来表示对象
(4)HashType:继承SetType,再实现了hashCode方法
注意点:
(1)从输出我们能够看见。在main的第一个test方法,它的输出是许多的对象id,并且里面出现了许多的反复。这是由于我们没有重写hashCode方法,在Object的hashCode方法里面。每个对象返回的hashcode都不一样。jvm认定都是不同的对象,因此我们加入多少对象进去,就会显示多少对象
(2)接着上面的解释,以下的HashType重写了hashCode方法。以id为标准,从上面的代码我们能够看见,id很可能反复,因此jvm就会去重。
我们能够翻开HashSet的源码,看看add方法:
private transient HashMap<E,Object> map;
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
对象是放到map里面,我们在翻开map的put方法:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
它里面是对照了hash值的,因此HashSet想实现去重,必须重写equals和hashcode方法。
(3)由于上面产生的值比較少,因此排序的特殊性没有表露出来。当我们添加创建的对象时。排序就会依照一定的顺序排列,而不是依照我们想象的顺序。
关于这样的排序,我们后面的章节会说到。
以下是样例代码:
package com.ray.ch15; import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set; public class Test<T> {
public static <T> Set<T> fill(Set<T> set, Class<T> type)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, SecurityException,
InvocationTargetException, NoSuchMethodException {
for (int i = 0; i < 20; i++) {
set.add(type.getConstructor(int.class).newInstance(i));
}
return set;
} public static <T> void test(Set<T> set, Class<T> type)
throws IllegalArgumentException, SecurityException,
InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
fill(set, type);
fill(set, type);
fill(set, type);
System.out.println(set);
} public static void main(String[] args) throws IllegalArgumentException,
SecurityException, InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
test(new HashSet<HashType>(), HashType.class);
}
} class SetType {
private int id = 0; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public SetType(int i) {
id = i;
} @Override
public String toString() {
return id + "";
} @Override
public boolean equals(Object obj) {
return obj instanceof SetType && (id == ((SetType) obj).id);
}
} class HashType extends SetType { public HashType(int i) {
super(i);
} @Override
public int hashCode() {
return getId();
}
}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 16, 19, 18]
总结:这一章节主要讲述了使用HashSet须要注意的地方。
这一章节就到这里,谢谢。
-----------------------------------
从头认识java-15.3 使用HashSet须要注意的地方的更多相关文章
- Java 集合系列 16 HashSet
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java set接口之HashSet集合原理讲解
Set接口 java.util.set接口继承自Collection接口,它与Collection接口中的方法基本一致, 并没有对 Collection接口进行功能上的扩充,只是比collection ...
- 从头认识java-15.5 使用LinkedHashSet须要注意的地方
再接着上一个章节.我们来聊一下使用LinkedHashSet须要注意的地方. LinkedHashSet特点: (1)元素是有顺序的 (2)元素是不反复的 (3)底层数据结构是依照链表的结构存储的 ( ...
- java源码之HashSet
1,HashSet介绍 1)HashSet 是一个没有重复元素的集合.2)它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素.3)HashSet是非同步的.如果多 ...
- Java集合框架之HashSet浅析
Java集合框架之HashSet浅析 一.HashSet综述: 1.1HashSet简介 位于java.util包下的HashSet是Java集合框架的重要成员,它在jdk1.8中定义如下: publ ...
- JDK 15 JAVA 15的新特性展望
目录 JEP 371: Hidden Classes JEP 372: 删除 Nashorn JavaScript Engine JEP 377: 新的垃圾回收器ZGC正式上线了 JEP 378: T ...
- Java 15 正式发布, 14 个新特性,刷新你的认知!!
JDK 15 2020/09/15 如期而至! 这个时间牛逼啊,和苹果发布会同天? OracleJDK 15 发布地址: https://www.oracle.com/java/technologie ...
- linux(centos8):安装java jdk 15 (java 15)
一,下载jdk15 官方网站: https://www.oracle.com/java/ 下载页面: https://www.oracle.com/cn/java/technologies/javas ...
- Java 中的 3 个双引号是什么语法?Java 15 刷新你的认知!
Java 中的 3 个双引号 """ 是什么语法? 这是 Java 15 新出的,刷新你的认知! 一.前言 在 Java 15 的推出的时候,Text Blocks 正式 ...
随机推荐
- jQuery Mobile页面跳转切换的几种方式
jQuery Mobile在移动开发中越来越受到欢迎. 而他的各个版本号也在持续不断的更新中.相同的我也非常喜欢它,它加快了我们开发HTML5的速度. 同一时候又具备jQuery一样的操作方法. 学起 ...
- VMware-workstation安装
下载:百度搜索VMware-workstation 开始安装:VMware-workstation-full_12.5.5.17738 更改安装目录F:\softwore\VMware\VMware ...
- Android自己定义View之组合控件 ---- LED数字时钟
先上图 LEDView效果如图所看到的. 之前看到一篇博客使用两个TextView实现了该效果.于是我想用自己定义控件的方式实现一个LEDView.使用时就可以直接使用该控件. 採用组合控件的方式,将 ...
- USACO 1.4 Mother's Milk
Mother's Milk Farmer John has three milking buckets of capacity A, B, and C liters. Each of the numb ...
- POJ 2346 DP or打表
这题 不算重复的数.. 就变成水题了. 思路: 1.打表 2.DP 打表的: // by SiriusRen #include <cstdio> using namespace std; ...
- 以SqlHelper为例论面向对象中封装的使用
引言: 在使用面向对象方法编写的程序中,会有一些工具类,如Utility,xxHelper等. 比如1)操作数据库的过程,一般步骤都是:1.准备数据库地址.表名等信息:2.建立连接:3.准备要执行sq ...
- form&method【POST~GET】
<form.../>中method属性指定了该表单是以哪种方式提交请求,有两种方式:GET请求方式和POST请求方式,默认是GET请求方式.两种方式的区别:get方式的请求是在浏览器地址栏 ...
- Jquery 随笔
jQuery中 遍历 var arr = ['a','b','c']; $.each(arr,function(k,v){ console.log(k); //键 console.log( ...
- PHP-输入账号密码进入网页
1. 2. 3. 4.(itcast.html步骤)随便一个本地网页代替即可
- AARRR:互联网创业者一定要掌握的指标
创业公司如何做数据分析?网站分析工具里的指标千百种,到底要从哪些数据入手呢?除了流量跟转换率,还有哪些数据跟公司成长有关呢?或许可以从了解AARRR Metrics开始.AARRR Metrics是由 ...