Set·无序,不重复

HashSet

特点:没有重复数据,数据不按存入的顺序输出。

HashSet由Hash表结构支持。不支持set的迭代顺序,不保证顺序。

但是Hash表结构查询速度很快。

创建集合使用代码:

Set<String> s = new HashSet<>();

代码演示:常用方法和遍历输出

import java.util.*;
public class TestHashSet {
public static void main(String[] args) {
m010赋值And遍历();
}
public static void m010赋值And遍历() {
System.out.println("=====赋值And遍历");
Set<String> s = new HashSet<>();
s.add("孙悟空");
s.add("小白龙");
s.add("猪八戒");
s.add("沙悟净");
s.add("孙悟空");
System.out.println("是否为空:" + s.isEmpty());
System.out.println("是否包含:" + s.contains("小白龙"));
System.out.println("移除:" + s.remove("小白龙"));
// (1)foreach:遍历set
for (String str : s) {
System.out.println(str);
}
// (2)迭代器:遍历set
Iterator<String> it = s.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println("Iterator : " + str);
}
// (3)*Java 8新增遍历方法
s.forEach(elm -> System.out.println("Lambda:" + elm));
}
}

Hash和Hash表

Hash

HashCode,是一个十进制整数,是对象的地址值(逻辑地址,不是物理地址)

Object类有一个方法,可以获取对象的Hash值。

public native int hashCode();

String重写了hashCode方法

    public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value; for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}

以至于有些不同字符串的hashCode相等(字符串还是不等的,无论==还是equals):

		System.out.println("重地".hashCode());
System.out.println("通话".hashCode());
System.out.println("--------------");
System.out.println("方面".hashCode());
System.out.println("树人".hashCode());
System.out.println("--------------");
System.out.println("儿女".hashCode());
System.out.println("农丰".hashCode());
System.out.println("--------------");
System.out.println("Ea".hashCode());
System.out.println("FB".hashCode());

Hash表

Java8之前:Hash表使用数组+链表;

Java8之后加入了红黑树,查询速度加快。

Hash表结构的示意图如下所示:

数组里存储的是HashCode。

HashCode相同的元素加入相同链表;

如果链表长度超过8,就转为红黑树以提高查询速度。

怎么才算重复?

HashSet中,元素不重复指“equals方法比较为true,且hashCode不同”。

下列示例代码中,只有equals为true、且hashCode相同的对象未重复存入Set中。

import java.util.*;
class A_equalsT {
public boolean equals(Object obj) {
return true;
}
}
class B_hash1 {
public int hashCode() {
return 1;
}
}
class C_hash2_equalsT {
public int hashCode() {
return 2;
}
public boolean equals(Object obj) {
return true;
}
}
public class TestSet怎么才算重复 {
public static void main(String[] args) {
Set<Object> _set = new HashSet<Object>();
_set.add(new A_equalsT());
_set.add(new A_equalsT());
_set.add(new B_hash1());
_set.add(new B_hash1());
_set.add(new C_hash2_equalsT());
_set.add(new C_hash2_equalsT());
for (Object object : _set) {
System.out.println(object);
}
}
}

运行结果:(C_hash2_equalsT只存入一份,说明被看作重复对象)

B_hash1@1
B_hash1@1
C_hash2_equalsT@2
A_equalsT@15db9742
A_equalsT@6d06d69c

HashSet存储自定义元素时,需要重写hashCode和equals方法,才能保证集合中对象的唯一性。

练习:

创建Student类,至少需要包含id、name。创建多个Student对象加入HashSet,如果学号(id)相同则不重复加入。

TreeSet

TreeSet支持两种排序方式,自然排序和定制排序。默认为自然排序,和HashSet的输出顺序不一样。

TreeSet使用红黑树存储元素(示例和下一小节一起)。

LinkedHashSet

Set也可以有序,这个LinkedHashSet就能按照输入顺序输出结果。

LinkedHashSet也是根据元素的hashCode值决定元素的存储位置,但是加了一条链表记录元素的存储顺序,这使得元素有序。

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
public class TestTree{
public static void main(String[] args) {
m020各种Set();
}
private static void m020各种Set() {
System.out.println("|-HashSet:");
Set<String> _set;
_set = new HashSet<String>();
_set.add("B");
_set.add("A");
_set.add("1");
_set.add("2");
_set.add(null);
printSet(_set);
System.out.println("|-TreeSet不接受空值:");
_set = new TreeSet<String>();
_set.add("B");
_set.add("A");
_set.add("1");
_set.add("2");
// _set.add(null);
printSet(_set);
System.out.println("|-LinkedHashSet:有序");
_set = new LinkedHashSet<String>();
_set.add("B");
_set.add("A");
_set.add("1");
_set.add("2");
_set.add(null);
printSet(_set);
}
private static void printSet(Set<String> _set) {
for (String str : _set) {
System.out.print(str + " ");
}
System.out.println();
}
}

|-HashSet:

null A 1 B 2

|-TreeSet不接受空值:

1 2 A B

|-LinkedHashSet:有序

B A 1 2 null

Set的性能

HashSet综合效率最高,LinkedHashSet因为有链表,遍历时会更快一些。TreeSet因为要维护红黑树,效率较低。

Java基础教程——Set的更多相关文章

  1. Java基础教程(18)--继承

    一.继承的概念   继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...

  2. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

  3. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  4. Java基础教程:网络编程

    Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...

  5. Java基础教程(5)--变量

    一.变量 1.变量的定义   正如上一篇教程<Java基础教程(4)--面向对象概念>中介绍的那样,对象将它的状态存在域中.但是你可能仍然有一些疑问,例如:命名一个域的规则和惯例是什么?除 ...

  6. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

  7. Java基础教程:泛型基础

    Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...

  8. Java基础教程:多线程基础(1)——基础操作

    Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...

  9. Java基础教程:反射基础

    Java基础教程:反射基础 引入反射 反射是什么 能够动态分析类能力的程序称为反射. 反射是一种很强大且复杂的机制. Class类 在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时 ...

  10. Java基础教程:多线程基础(4)——Lock的使用

    Java基础教程:多线程基础(4)——Lock的使用 快速开始 Java 5中Lock对象的也能实现同步的效果,而且在使用上更加方便. 本节重点的2个知识点是:ReentrantLock类的使用和Re ...

随机推荐

  1. uni-app h5端跨域问题解决

    例如我现在的项目运行在 http://localhost:8080,而我有个接口是 https://service.picasso.adesk.com/v1/wallpaper/album,发起请求就 ...

  2. Linux 系统编程 学习:04-进程间通信2:System V IPC(1)

    Linux 系统编程 学习:04-进程间通信2:System V IPC(1) 背景 上一讲 进程间通信:Unix IPC-信号中,我们介绍了Unix IPC中有关信号的概念,以及如何使用. IPC的 ...

  3. Python+Django实现微信扫码支付流程

    Python+Django实现微信扫码支付流程 关注公众号"轻松学编程"了解更多. 获取源码可以加我微信[1257309054],文末有二维码. [微信公众号支付官网]https: ...

  4. python模块导入(包)

    模块 关注公众号"轻松学编程"了解更多. 1.1. 模块的概述 ​ 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里的代码就会越来越长,越来越不容易维护. 为了编写可维 ...

  5. 辨析:IIR(Infinite Impulse Response)与FIR(Finite Impulse Response)

    IIR和FIR系统描述的是系统的抽样响应特性,其中$ x(n)=\delta(n) $ 举例:一个平均器的系统是FIR系统,因为它的抽样响应仅在变量n取某3个值的时候有值,是有限长的:一阶自回归模型由 ...

  6. 1.流程控制--if

    流程控制--if -*- coding:utf-8 -*- #定义字符编码 1.判断条件if age = input("输入年龄:") #将交互式输入内容赋值给age,默认内容为字 ...

  7. python3批量修改文件后缀名

    import os # 原文件后缀名 suffix_name = '.jar.src.zip' # 新文件后缀名 nwe_suffix_name = '.jar' def foo(path1): fi ...

  8. java实现一个简单的单链表反转

    自定义一个单链表,实现链表反转: 1.普通方法实现 2.递归方式实现 package listNode; public class ReverseNode { public static void m ...

  9. Statistical physics approaches to the complex Earth system(相关系统建模理念方法的摘要)

    本文翻译自"Statistical physics approaches to the complex Earth system",其虽然是针对复杂地球系统的统计物理方法的综述,但 ...

  10. NIO源码分析:SelectionKey

    SelectionKey SelectionKey,选择键,在每次通道注册到选择器上时都会创建一个SelectionKey储存在该选择器上,该SelectionKey保存了注册的通道.注册的选择器.通 ...