这一章节我们来讨论一下使用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须要注意的地方的更多相关文章

  1. Java 集合系列 16 HashSet

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  2. Java set接口之HashSet集合原理讲解

    Set接口 java.util.set接口继承自Collection接口,它与Collection接口中的方法基本一致, 并没有对 Collection接口进行功能上的扩充,只是比collection ...

  3. 从头认识java-15.5 使用LinkedHashSet须要注意的地方

    再接着上一个章节.我们来聊一下使用LinkedHashSet须要注意的地方. LinkedHashSet特点: (1)元素是有顺序的 (2)元素是不反复的 (3)底层数据结构是依照链表的结构存储的 ( ...

  4. java源码之HashSet

    1,HashSet介绍 1)HashSet 是一个没有重复元素的集合.2)它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素.3)HashSet是非同步的.如果多 ...

  5. Java集合框架之HashSet浅析

    Java集合框架之HashSet浅析 一.HashSet综述: 1.1HashSet简介 位于java.util包下的HashSet是Java集合框架的重要成员,它在jdk1.8中定义如下: publ ...

  6. JDK 15 JAVA 15的新特性展望

    目录 JEP 371: Hidden Classes JEP 372: 删除 Nashorn JavaScript Engine JEP 377: 新的垃圾回收器ZGC正式上线了 JEP 378: T ...

  7. Java 15 正式发布, 14 个新特性,刷新你的认知!!

    JDK 15 2020/09/15 如期而至! 这个时间牛逼啊,和苹果发布会同天? OracleJDK 15 发布地址: https://www.oracle.com/java/technologie ...

  8. linux(centos8):安装java jdk 15 (java 15)

    一,下载jdk15 官方网站: https://www.oracle.com/java/ 下载页面: https://www.oracle.com/cn/java/technologies/javas ...

  9. Java 中的 3 个双引号是什么语法?Java 15 刷新你的认知!

    Java 中的 3 个双引号 """ 是什么语法? 这是 Java 15 新出的,刷新你的认知! 一.前言 在 Java 15 的推出的时候,Text Blocks 正式 ...

随机推荐

  1. Methods Collection of Enumerating Com Port in Windows, by C

    According to this stack overflow thread, PJ Naughter has implemented 9 methods to emunerate com port ...

  2. jquery 弹窗插件 layer

    jquery 弹窗插件 layer 官网:http://sentsin.com/jquery/layer/ 1 <!DOCTYPE html PUBLIC "-//W3C//DTD H ...

  3. gemm() 与 gesvd() 到矩阵求逆(inverse)(根据 SVD 分解和矩阵乘法求矩阵的逆)

    可逆方阵 A 的逆记为,A−1,需满足 AA−1=I. 在 BLAS 的各种实现中,一般都不会直接给出 matrix inverse 的直接实现,其实矩阵(方阵)的逆是可以通过 gemm()和gesv ...

  4. RAC中的各种IP-PUBLIC-VIP-Private-SCAN IP

    RAC中的各种IP-PUBLIC-VIP-Private-SCAN IP   1.PUBLIC和VIP Oracle RAC中每个节点都有一个虚拟IP,简称VIP, 与公网PUBLIC  IP在同一个 ...

  5. go并发设计模式 --资源生成器模式

    1.简单的生成器 package main import ( "fmt" "math/rand" ) func GenerateIntA()chan int { ...

  6. [转] Java 插入表记录后得到自增的id (附3种方法代码)

    转自:https://blog.csdn.net/yaerfeng/article/details/7231093 在MySQL中,使用auto_increment类型的id字段作为表的主键,并用它作 ...

  7. Redis的配置文件详解

    daemonize:如需要在后台运行,把该项的值改为yes pdifile:把pid文件放在/var/run/redis.pid,可以配置到其他地址 bind:指定redis只接收来自该IP的请求,如 ...

  8. 高并发之后端优化(PHP)

    页面静态化 使用模板引擎 可以使用Smarty的缓存机制生成静态HTML缓存文件 $smarty->cachedir=$ROOT·"/cache"://缓存目录 $smart ...

  9. T7315 yyy矩阵折叠(长)

    题目背景 全场基本暴零 题目描述 输入输出格式 输入格式: 如图 输出格式: 如图 输入输出样例 输入样例#1: 2 2 1 -2 3 -4 输出样例#1: 4 输入样例#2: 2 5 1 -2 -3 ...

  10. CSS3背景 制作导航菜单综合练习题

    CSS3背景 制作导航菜单综合练习题 小伙伴们,根据所学知识,使用CSS3实现下图的导航菜单效果 任务 1.制作导航圆角 提示:使用border-radius实现圆角 2.制作导航立体风格 提示:使用 ...